#include "stdafx.h"

#include "Lua-Main.h"
#include "Defines.h"

using namespace luabridge;

namespace {

lua_State* Interpreter = 0;

const int DefaultBuffer = 512;

template <class CHECK_A_, class CHECK_B_>
CHECK_B_ CheckResult (CHECK_A_ aCurrent, CHECK_B_ aExpected)
{
    if (aCurrent != static_cast<CHECK_A_>(aExpected)) {
        luaL_error(Interpreter, "Unexpected return value: %d", aCurrent);
    }

    return static_cast<CHECK_B_> (aCurrent);
}

template <class CHECK_A_, class CHECK_B_>
CHECK_B_ CheckResult (CHECK_A_ aCurrent, CHECK_B_ aExpected1, CHECK_B_ aExpected2)
{
    return static_cast<CHECK_B_> (CheckResult (aCurrent, aExpected1),
                                  CheckResult (aCurrent, aExpected2));
}

template <class CHECK_A_, class CHECK_B_>
CHECK_B_ CheckResult (CHECK_A_ aCurrent, CHECK_B_ aExpected1, CHECK_B_ aExpected2, CHECK_B_ aExpected3)
{
    return static_cast<CHECK_B_> (CheckResult (aCurrent, aExpected1),
                                  CheckResult (aCurrent, aExpected2),
                                  CheckResult (aCurrent, aExpected3));
}

template <class CHECK_A_, class CHECK_B_>
CHECK_B_ CheckResult (CHECK_A_ aCurrent, CHECK_B_ aExpected1, CHECK_B_ aExpected2, CHECK_B_ aExpected3, CHECK_B_ aExpected4)
{
    return static_cast<CHECK_B_> (CheckResult (aCurrent, aExpected1),
                                  CheckResult (aCurrent, aExpected2),
                                  CheckResult (aCurrent, aExpected3),
                                  CheckResult (aCurrent, aExpected4));
}

template <class CHECK_A_, class CHECK_B_>
CHECK_B_ CheckResult (CHECK_A_ aCurrent, CHECK_B_ aExpected1, CHECK_B_ aExpected2, CHECK_B_ aExpected3, CHECK_B_ aExpected4, CHECK_B_ aExpected5)
{
    return static_cast<CHECK_B_> (CheckResult (aCurrent, aExpected1),
                                  CheckResult (aCurrent, aExpected2),
                                  CheckResult (aCurrent, aExpected3),
                                  CheckResult (aCurrent, aExpected4),
                                  CheckResult (aCurrent, aExpected5));
}

template <class CHECK_A_, class CHECK_B_>
CHECK_B_ CheckResult (CHECK_A_ aCurrent, CHECK_B_ aExpected1, CHECK_B_ aExpected2, CHECK_B_ aExpected3, CHECK_B_ aExpected4, CHECK_B_ aExpected5, CHECK_B_ aExpected6)
{
    return static_cast<CHECK_B_> (CheckResult (aCurrent, aExpected1),
                                  CheckResult (aCurrent, aExpected2),
                                  CheckResult (aCurrent, aExpected3),
                                  CheckResult (aCurrent, aExpected4),
                                  CheckResult (aCurrent, aExpected5),
                                  CheckResult (aCurrent, aExpected6));
}

struct MsifilehashinfoHelper
{
  template <unsigned index>
  static ULONG get (MSIFILEHASHINFO const* aInfo)
  {
    return aInfo->dwData [index];
  }

  template <unsigned index>
  static void set (MSIFILEHASHINFO* aInfo, ULONG aValue)
  {
    aInfo->dwData [index] = aValue;
  }
};

namespace Installproperty {

const char* Packagename = INSTALLPROPERTY_PACKAGENAME;
const char* Transforms = INSTALLPROPERTY_TRANSFORMS;
const char* Language = INSTALLPROPERTY_LANGUAGE;
const char* Productname = INSTALLPROPERTY_PRODUCTNAME;
const char* Assignmenttype = INSTALLPROPERTY_ASSIGNMENTTYPE;
const char* Instancetype = INSTALLPROPERTY_INSTANCETYPE;
const char* Authorized_lua_app = INSTALLPROPERTY_AUTHORIZED_LUA_APP;
const char* Packagecode = INSTALLPROPERTY_PACKAGECODE;
const char* Version = INSTALLPROPERTY_VERSION;
const char* Producticon = INSTALLPROPERTY_PRODUCTICON;
const char* Installedproductname = INSTALLPROPERTY_INSTALLEDPRODUCTNAME;
const char* Versionstring = INSTALLPROPERTY_VERSIONSTRING;
const char* Helplink = INSTALLPROPERTY_HELPLINK;
const char* Helptelephone = INSTALLPROPERTY_HELPTELEPHONE;
const char* Installlocation = INSTALLPROPERTY_INSTALLLOCATION;
const char* Installsource = INSTALLPROPERTY_INSTALLSOURCE;
const char* Installdate = INSTALLPROPERTY_INSTALLDATE;
const char* Publisher = INSTALLPROPERTY_PUBLISHER;
const char* Localpackage = INSTALLPROPERTY_LOCALPACKAGE;
const char* Urlinfoabout = INSTALLPROPERTY_URLINFOABOUT;
const char* Urlupdateinfo = INSTALLPROPERTY_URLUPDATEINFO;
const char* Versionminor = INSTALLPROPERTY_VERSIONMINOR;
const char* Versionmajor = INSTALLPROPERTY_VERSIONMAJOR;
const char* Productid = INSTALLPROPERTY_PRODUCTID;
const char* Regcompany = INSTALLPROPERTY_REGCOMPANY;
const char* Regowner = INSTALLPROPERTY_REGOWNER;
const char* Installedlanguage = INSTALLPROPERTY_INSTALLEDLANGUAGE;
const char* Uninstallable = INSTALLPROPERTY_UNINSTALLABLE;
const char* Productstate = INSTALLPROPERTY_PRODUCTSTATE;
const char* Patchstate = INSTALLPROPERTY_PATCHSTATE;
const char* Patchtype = INSTALLPROPERTY_PATCHTYPE;
const char* Luaenabled = INSTALLPROPERTY_LUAENABLED;
const char* Displayname = INSTALLPROPERTY_DISPLAYNAME;
const char* Moreinfourl = INSTALLPROPERTY_MOREINFOURL;

}

namespace Installmessage {

unsigned int Fatalexit      = 0x00000000L;
unsigned int Error          = 0x01000000l;
unsigned int Warning        = 0x02000000l;
unsigned int User           = 0x03000000l;
unsigned int Info           = 0x04000000l;
unsigned int Filesinuse     = 0x05000000l;
unsigned int Resolvesource  = 0x06000000l;
unsigned int Outofdiskspace = 0x07000000l;
unsigned int Actionstart    = 0x08000000l;
unsigned int Actiondata     = 0x09000000l;
unsigned int Progress       = 0x0a000000l;
unsigned int Commondata     = 0x0b000000l;
unsigned int Initialize     = 0x0c000000l;
unsigned int Terminate      = 0x0d000000l;
unsigned int Showdialog     = 0x0e000000l;
unsigned int Performance    = 0x0f000000l;
unsigned int Rmfilesinuse   = 0x19000000l;
unsigned int Installstart   = 0x1a000000l;
unsigned int Installend     = 0x1b000000l;

}

namespace Installuilevel {

unsigned int Nochange = 0;
unsigned int Default  = 1;
unsigned int None     = 2;
unsigned int Basic    = 3;
unsigned int Reduced  = 4;
unsigned int Full     = 5;
unsigned int Enddialog    = 0x80;
unsigned int Progressonly = 0x40;
unsigned int Hidecancel   = 0x20;
unsigned int Sourceresonly = 0x100;
unsigned int Uaconly = 0x200;

}

namespace Installstate {

int Notused      = -7;
int Badconfig    = -6;
int Incomplete   = -5;
int Sourceabsent = -4;
int Moredata     = -3;
int Invalidarg   = -2;
int Unknown      = -1;
int Broken       =  0;
int Advertised   =  1;
int Removed      =  1;
int Absent       =  2;
int Local        =  3;
int Source       =  4;
int Default      =  5;

}

namespace Userinfostate {

int Moredata   = -3;
int Invalidarg = -2;
int Unknown    = -1;
int Absent     =  0;
int Present    =  1;

}

namespace Installlevel {

unsigned int Default = 0;
unsigned int Minimum = 1;
unsigned int Maximum = 0xFFFF;

}

namespace Reinstallmode {

unsigned int Repair           = 0x00000001;
unsigned int Filemissing      = 0x00000002;
unsigned int Fileolderversion = 0x00000004;
unsigned int Fileequalversion = 0x00000008;
unsigned int Fileexact        = 0x00000010;
unsigned int Fileverify       = 0x00000020;
unsigned int Filereplace      = 0x00000040;
unsigned int Machinedata      = 0x00000080;
unsigned int Userdata         = 0x00000100;
unsigned int Shortcut         = 0x00000200;
unsigned int Package          = 0x00000400;

}

namespace Installogmode {

unsigned int Fatalexit      = (1 << (INSTALLMESSAGE_FATALEXIT      >> 24));
unsigned int Error          = (1 << (INSTALLMESSAGE_ERROR          >> 24));
unsigned int Warning        = (1 << (INSTALLMESSAGE_WARNING        >> 24));
unsigned int User           = (1 << (INSTALLMESSAGE_USER           >> 24));
unsigned int Info           = (1 << (INSTALLMESSAGE_INFO           >> 24));
unsigned int Resolvesource  = (1 << (INSTALLMESSAGE_RESOLVESOURCE  >> 24));
unsigned int Outofdiskspace = (1 << (INSTALLMESSAGE_OUTOFDISKSPACE >> 24));
unsigned int Actionstart    = (1 << (INSTALLMESSAGE_ACTIONSTART    >> 24));
unsigned int Actiondata     = (1 << (INSTALLMESSAGE_ACTIONDATA     >> 24));
unsigned int Commondata     = (1 << (INSTALLMESSAGE_COMMONDATA     >> 24));
unsigned int Propertydump   = (1 << (INSTALLMESSAGE_PROGRESS       >> 24));
unsigned int Verbose        = (1 << (INSTALLMESSAGE_INITIALIZE     >> 24));
unsigned int Extradebug     = (1 << (INSTALLMESSAGE_TERMINATE      >> 24));
unsigned int Logonlyonerror = (1 << (INSTALLMESSAGE_SHOWDIALOG     >> 24));
unsigned int Logperformance = (1 << (INSTALLMESSAGE_PERFORMANCE    >> 24));
unsigned int Progress       = (1 << (INSTALLMESSAGE_PROGRESS       >> 24));
unsigned int Initialize     = (1 << (INSTALLMESSAGE_INITIALIZE     >> 24));
unsigned int Terminate      = (1 << (INSTALLMESSAGE_TERMINATE      >> 24));
unsigned int Showdialog     = (1 << (INSTALLMESSAGE_SHOWDIALOG     >> 24));
unsigned int Filesinuse     = (1 << (INSTALLMESSAGE_FILESINUSE     >> 24));
unsigned int Rmfilesinuse   = (1 << (INSTALLMESSAGE_RMFILESINUSE   >> 24));
unsigned int Installstart   = (1 << (INSTALLMESSAGE_INSTALLSTART   >> 24));
unsigned int Installend     = (1 << (INSTALLMESSAGE_INSTALLEND     >> 24));

}

namespace Installlogattributes {

unsigned int Append            = (1 << 0);
unsigned int Flusheachline     = (1 << 1);

}

namespace Installfeatureattribute {

unsigned int Favorlocal             = 1 << 0;
unsigned int Favorsource            = 1 << 1;
unsigned int Followparent           = 1 << 2;
unsigned int Favoradvertise         = 1 << 3;
unsigned int Disallowadvertise      = 1 << 4;
unsigned int Nounsupportedadvertise = 1 << 5;

}

namespace Installmode {

int Nodetection_any      = -4;
int Nosourceresolution   = -3;
int Nodetection          = -2;
int Existing             = -1;
int Default              =  0;

}

namespace Msipatchstate {

unsigned int Invalid     =  0;
unsigned int Applied     =  1;
unsigned int Superseded  =  2;
unsigned int Obsoleted   =  4;
unsigned int Registered  =  8;
unsigned int All         =  (MSIPATCHSTATE_APPLIED | MSIPATCHSTATE_SUPERSEDED | MSIPATCHSTATE_OBSOLETED | MSIPATCHSTATE_REGISTERED);

}

namespace Msiinstallcontext {

unsigned int Firstvisible   =  0;
unsigned int None           =  0;
unsigned int Usermanaged    =  1;
unsigned int Userunmanaged  =  2;
unsigned int Machine        =  4;
unsigned int All            =  (MSIINSTALLCONTEXT_USERMANAGED | MSIINSTALLCONTEXT_USERUNMANAGED | MSIINSTALLCONTEXT_MACHINE);
unsigned int Allusermanaged =  8;

}

namespace Msipatchdatatype {

unsigned int Datatype_patchfile = 0;
unsigned int Datatype_xmlpath   = 1;
unsigned int Datatype_xmlblob   = 2;

}

namespace Scriptflags {

unsigned int Cacheinfo                = 0x00000001L;
unsigned int Shortcuts                = 0x00000004L;
unsigned int Machineassign            = 0x00000008L;
unsigned int Regdata_cnfginfo         = 0x00000020L;
unsigned int Validate_transforms_list = 0x00000040L;
unsigned int Regdata_classinfo        = 0x00000080L;
unsigned int Regdata_extensioninfo    = 0x00000100L;
unsigned int Regdata_appinfo          = 0x00000010L;
unsigned int Regdata                  = SCRIPTFLAGS_REGDATA_APPINFO | SCRIPTFLAGS_REGDATA_CNFGINFO;

}

namespace Advertiseflags {

unsigned int Machineassign   =    0;
unsigned int Userassign      =    1;

}

namespace Installtype {

unsigned int Default            =    0;
unsigned int Network_image      =    1;
unsigned int Single_instance    =    2;

}

namespace Msiarchitectureflags {

unsigned int X86   = 0x00000001L;
unsigned int Ia64  = 0x00000002L;
unsigned int AMD64  = 0x00000004L;

}

namespace Msiopenpackageflags {

unsigned int Ignoremachinestate = 0x00000001L;

}

namespace Msiadvertiseoptionflags {

unsigned int Instance = 0x00000001L;

}

namespace Msisourcetype {

unsigned int Unknown = 0x00000000L;
unsigned int Network = 0x00000001L;
unsigned int Url     = 0x00000002L;
unsigned int Media   = 0x00000004L;

}

namespace Msicode {

unsigned int Product = 0x00000000L;
unsigned int Patch   = 0x40000000L;

}

namespace Msitransaction {

unsigned int Chain_embeddedui = 0x00000001L;
unsigned int Join_existing_embeddedui = 0x00000002L;

}

namespace Msitransactionstate {

unsigned int Rollback = 0x00000000L;
unsigned int Commit   = 0x00000001L;

}

namespace Msidbstate
{

int Error    =-1;
int Read     = 0;
int Write    = 1;

}

namespace Msimodify
{

int Seek             =-1;
int Refresh          = 0;
int Insert           = 1;
int Update           = 2;
int Assign           = 3;
int Replace          = 4;
int Merge            = 5;
int Delete           = 6;
int Insert_temporary = 7;
int Validate         = 8;
int Validate_new     = 9;
int Validate_field   = 10;
int Validate_delete  = 11;

}

namespace Msicolinfo
{

unsigned int Names = 0;
unsigned int Types = 1;

}

namespace Msicondition
{

unsigned int False = 0;
unsigned int True  = 1;
unsigned int None  = 2;
unsigned int Error = 3;

}

namespace Msicosttree
{

unsigned int Selfonly = 0;
unsigned int Children = 1;
unsigned int Parents  = 2;
unsigned int Reserved = 3;

}

namespace Msidberror
{

int Invalidarg        = -3;
int Moredata          = -2;
int Functionerror     = -1;
int Noerror           = 0;
int Duplicatekey      = 1;
int Required          = 2;
int Badlink           = 3;
int Overflow          = 4;
int Underflow         = 5;
int Notinset          = 6;
int Badversion        = 7;
int Badcase           = 8;
int Badguid           = 9;
int Badwildcard       = 10;
int Badidentifier     = 11;
int Badlanguage       = 12;
int Badfilename       = 13;
int Badpath           = 14;
int Badcondition      = 15;
int Badformatted      = 16;
int Badtemplate       = 17;
int Baddefaultdir     = 18;
int Badregpath        = 19;
int Badcustomsource   = 20;
int Badproperty       = 21;
int Missingdata       = 22;
int Badcategory       = 23;
int Badkeytable       = 24;
int Badmaxminvalues   = 25;
int Badcabinet        = 26;
int Badshortcut       = 27;
int Stringoverflow    = 28;
int Badlocalizeattrib = 29;

}

namespace Msirunmode
{

unsigned int Admin           =  0;
unsigned int Advertise       =  1;
unsigned int Maintenance     =  2;
unsigned int Rollbackenabled =  3;
unsigned int Logenabled      =  4;
unsigned int Operations      =  5;
unsigned int Rebootatend     =  6;
unsigned int Rebootnow       =  7;
unsigned int Cabinet         =  8;
unsigned int Sourceshortnames=  9;
unsigned int Targetshortnames= 10;
unsigned int Reserved11      = 11;
unsigned int Windows9x       = 12;
unsigned int Zawenabled      = 13;
unsigned int Reserved14      = 14;
unsigned int Reserved15      = 15;
unsigned int Scheduled       = 16;
unsigned int Rollback        = 17;
unsigned int Commit          = 18;

}

namespace Msitransform_error
{

unsigned int Error_addexistingrow   =  0x00000001;
unsigned int Error_delmissingrow    =  0x00000002;
unsigned int Error_addexistingtable =  0x00000004;
unsigned int Error_delmissingtable  =  0x00000008;
unsigned int Error_updatemissingrow =  0x00000010;
unsigned int Error_changecodepage   =  0x00000020;
unsigned int Error_viewtransform    =  0x00000100;

}

namespace Msitransform_validate
{

unsigned int Validate_language                   = 0x00000001;
unsigned int Validate_product                    = 0x00000002;
unsigned int Validate_platform                   = 0x00000004;
unsigned int Validate_majorversion               = 0x00000008;
unsigned int Validate_minorversion               = 0x00000010;
unsigned int Validate_updateversion              = 0x00000020;
unsigned int Validate_newlessbaseversion         = 0x00000040;
unsigned int Validate_newlessequalbaseversion    = 0x00000080;
unsigned int Validate_newequalbaseversion        = 0x00000100;
unsigned int Validate_newgreaterequalbaseversion = 0x00000200;
unsigned int Validate_newgreaterbaseversion      = 0x00000400;
unsigned int Validate_upgradecode                = 0x00000800;

}

UINT LMsiCloseHandle (MSIHANDLE aHandle)
{
    return MsiCloseHandle(aHandle);
}

UINT LMsiCloseAllHandles ()
{
    return MsiCloseAllHandles();
}

UINT LMsiEnableLog(
	DWORD     dwLogMode,
	LPCSTR  szLogFile,
	DWORD     dwLogAttributes)
{
  return MsiEnableLog(dwLogMode, szLogFile, dwLogAttributes);
}

INSTALLSTATE LMsiQueryProductState(
	LPCSTR  szProduct)
{
    return MsiQueryProductState(szProduct);
}

String LMsiGetProductInfo(
	LPCSTR   szProduct,
	LPCSTR   szAttribute
)
{
    String Result;
    Result.resize (1);

    DWORD Size = 0;

    CheckResult (MsiGetProductInfo (szProduct, szAttribute, &Result[0], &Size), ERROR_SUCCESS, ERROR_MORE_DATA);

    ++Size;
    Result.resize (Size);

    CheckResult (MsiGetProductInfo (szProduct, szAttribute, &Result[0], &Size), ERROR_SUCCESS);

    return Result;
}

String LMsiGetProductInfoEx(
		LPCSTR szProductCode,
		LPCSTR szUserSid,
		MSIINSTALLCONTEXT dwContext,
		LPCSTR szProperty
)
{
    String Result;
    Result.resize (1);
    DWORD Size = 0;

    CheckResult (MsiGetProductInfoEx (szProductCode, szUserSid, dwContext, szProperty, &Result[0], &Size), ERROR_SUCCESS, ERROR_MORE_DATA);

    ++Size;
    Result.resize (Size);

    CheckResult (MsiGetProductInfoEx (szProductCode, szUserSid, dwContext, szProperty, &Result[0], &Size), ERROR_SUCCESS);

    return Result;
}

UINT LMsiInstallProduct(
	LPCSTR      szPackagePath,
	LPCSTR      szCommandLine
)
{
    return MsiInstallProduct(szPackagePath, szCommandLine);
}

UINT LMsiConfigureProduct(
	LPCSTR       szProduct,
	int          iInstallLevel,
	INSTALLSTATE eInstallState
)
{
    return MsiConfigureProduct(szProduct, iInstallLevel, eInstallState);
}

UINT LMsiConfigureProductEx(
	LPCSTR       szProduct,
	int          iInstallLevel,
	INSTALLSTATE eInstallState,
	LPCSTR       szCommandLine
)
{
    return MsiConfigureProductEx(szProduct, iInstallLevel, eInstallState, szCommandLine);
}

UINT LMsiReinstallProduct(
	LPCSTR      szProduct,
	DWORD       szReinstallMode
)
{
    return MsiReinstallProduct(szProduct, szReinstallMode);
}

UINT LMsiAdvertiseProductEx(
	LPCSTR	szPackagePath,
	LPCSTR    szScriptfilePath,
	LPCSTR    szTransforms,
	LANGID      lgidLanguage,
	DWORD       dwPlatform,
	DWORD       dwOptions)
{
    return MsiAdvertiseProductEx(szPackagePath, szScriptfilePath, szTransforms, lgidLanguage, dwPlatform, dwOptions);
}

UINT LMsiAdvertiseProduct(
	LPCSTR      szPackagePath,
	LPCSTR      szScriptfilePath,
	LPCSTR      szTransforms,
	LANGID      lgidLanguage)
{
    return MsiAdvertiseProduct(szPackagePath, szScriptfilePath, szTransforms, lgidLanguage);
}

UINT LMsiProcessAdvertiseScript(
	LPCSTR      szScriptFile,
	LPCSTR      szIconFolder,
	HKEY         hRegData,
	BOOL         fShortcuts,
	BOOL         fRemoveItems)
{
    return MsiProcessAdvertiseScript(szScriptFile, szIconFolder, hRegData, fShortcuts, fRemoveItems);
}

UINT LMsiAdvertiseScript(
	LPCSTR      szScriptFile,
	DWORD         dwFlags,
	PHKEY         phRegData,
	BOOL          fRemoveItems)
{
    return MsiAdvertiseScript(szScriptFile, dwFlags, phRegData, fRemoveItems);
}

int LMsiGetProductInfoFromScript(lua_State* aState)
{
    String ScriptFile = luaL_checklstring(aState, 1, 0);
    _TCHAR ProductCode[MAX_GUID_CHARS + 1] = {0};
    LANGID Language;
    DWORD Version;
    _TCHAR ProductName[DefaultBuffer] = {0};
    DWORD ProductNameLength = DefaultBuffer;
    _TCHAR PackagePath[MAX_PATH] = {0};
    DWORD PackagePathLength = MAX_PATH;

    CheckResult (MsiGetProductInfoFromScript (ScriptFile.c_str (), ProductCode, &Language, &Version, ProductName, &ProductNameLength, PackagePath, &PackagePathLength), ERROR_SUCCESS);

    lua_pushstring(aState, ProductCode);
    lua_pushinteger(aState, Language);
    lua_pushinteger(aState, Version);
    lua_pushstring(aState, ProductName);
    lua_pushstring(aState, PackagePath);

    return 5;
}

String LMsiGetProductCode(
	LPCSTR   szComponent)
{
    _TCHAR Buffer[MAX_GUID_CHARS + 1] = {0};
    CheckResult(MsiGetProductCode(szComponent, Buffer), ERROR_SUCCESS);

    return Buffer;
}

int LMsiGetUserInfo(lua_State* aState)
{
    String Product = luaL_checkstring(aState, 1);

    _TCHAR UserName[DefaultBuffer] = {0};
    DWORD UserNameLength = DefaultBuffer;
    _TCHAR CompanyName[DefaultBuffer] = {0};
    DWORD CompanyNameLength = DefaultBuffer;
    _TCHAR ProductSerial[DefaultBuffer] = {0};
    DWORD ProductSerialLength = DefaultBuffer;

    UINT Check = MsiGetUserInfo (Product.c_str (), UserName, &UserNameLength, CompanyName, &CompanyNameLength, ProductSerial, &ProductSerialLength);

    CheckResult(Check, USERINFOSTATE_ABSENT, USERINFOSTATE_PRESENT);

    if (Check == USERINFOSTATE_PRESENT) {
        lua_pushinteger(aState, USERINFOSTATE_PRESENT);
        lua_pushstring(aState, UserName);
        lua_pushstring(aState, CompanyName);
        lua_pushstring(aState, ProductSerial);

        return 4;
    }

    lua_pushinteger(aState, USERINFOSTATE_ABSENT);
    return 1;
}

UINT LMsiCollectUserInfo(
	LPCSTR  szProduct)
{
    return MsiCollectUserInfo (szProduct);
}

UINT LMsiApplyPatch(
	LPCSTR szPatchPackage,
	LPCSTR szInstallPackage,
	INSTALLTYPE eInstallType,
	LPCSTR szCommandLine)
{
    return MsiApplyPatch(szPatchPackage, szInstallPackage, eInstallType, szCommandLine);
}

String LMsiGetPatchInfo(
	LPCSTR szPatch,
	LPCSTR szAttribute)
{
    _TCHAR Buffer[DefaultBuffer] = {0};
    DWORD BufferLength = DefaultBuffer;

    CheckResult (MsiGetPatchInfo(szPatch, szAttribute, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}

int LMsiEnumPatches(lua_State* aState)
{
    String Product = luaL_checkstring(aState, 1);
    int Index = luaL_checkint(aState, 2);
    _TCHAR Guid[MAX_GUID_CHARS + 1] = {0};
    _TCHAR Transforms[DefaultBuffer] = {0};
    DWORD TransformsLength = DefaultBuffer;

    UINT Check = MsiEnumPatches (Product.c_str (), Index, Guid, Transforms, &TransformsLength);

    CheckResult (Check, ERROR_SUCCESS, ERROR_NO_MORE_ITEMS);

    if (Check == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushstring(aState, Guid);
        lua_pushstring(aState, Transforms);

        return 3;
    }

    lua_pushboolean(aState, false);
    return 1;
}

UINT LMsiRemovePatches(
	LPCSTR szPatchList,
	LPCSTR szProductCode,
	INSTALLTYPE eUninstallType,
	LPCSTR szPropertyList)
{
    return MsiRemovePatches(szPatchList, szProductCode, eUninstallType, szPropertyList);
}

String LMsiExtractPatchXMLData(
	LPCSTR szPatchPath)
{
    _TCHAR Buffer[DefaultBuffer * 2] = {0};
    DWORD  BufferLength = DefaultBuffer * 2;

    CheckResult(MsiExtractPatchXMLData(szPatchPath, 0, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}

String LMsiGetPatchInfoEx(
        LPCSTR szPatchCode,
        LPCSTR szProductCode,
        LPCSTR szUserSid,
        MSIINSTALLCONTEXT dwContext,
        LPCSTR szProperty)
{
    _TCHAR Buffer[DefaultBuffer * 2] = {0};
    DWORD  BufferLength = DefaultBuffer * 2;

    CheckResult (MsiGetPatchInfoEx(szPatchCode, szProductCode, szUserSid, dwContext, szProperty, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}

UINT LMsiApplyMultiplePatches(
        LPCSTR szPatchPackages,
        LPCSTR szProductCode,
        LPCSTR szPropertiesList)
{
    return MsiApplyMultiplePatches (szPatchPackages, szProductCode, szPropertiesList);
}

int LMsiDeterminePatchSequence(lua_State* aState)
{
    const int FirstStructIndex = 3;

	DWORD InfoCount = lua_gettop (aState) - FirstStructIndex;
	luaL_argcheck (aState, InfoCount > 0, 1, "at least one PatchInfo is required");
	String ProductCode = luaL_checkstring (aState, 1);
	String UserSid = luaL_checkstring (aState, 2);
	MSIINSTALLCONTEXT Context = (MSIINSTALLCONTEXT)luaL_checkint (aState, 3);

	std::vector<MSIPATCHSEQUENCEINFO> Infos;
	Infos.resize(InfoCount);

	for (DWORD Index = 1; Index <= InfoCount; ++Index) {
        Infos.push_back(*((MSIPATCHSEQUENCEINFO*)lua_touserdata(aState, Index + FirstStructIndex)));
	}

	lua_pushinteger(aState, MsiDeterminePatchSequence (ProductCode.c_str (), UserSid.c_str (), Context, InfoCount, &Infos[0]));

	return 1;
}

int LMsiDetermineApplicablePatches(lua_State* aState)
{
    const int FirstStructIndex = 1;

	DWORD InfoCount = lua_gettop (aState) - FirstStructIndex;
	luaL_argcheck (aState, InfoCount > 0, 1, "at least one PatchInfo is required");
	String ProductPackagePath = luaL_checkstring (aState, 1);

	std::vector<MSIPATCHSEQUENCEINFO> Infos;
	Infos.resize(InfoCount);

	for (DWORD Index = 1; Index <= InfoCount; ++Index) {
        Infos.push_back(*((MSIPATCHSEQUENCEINFO*)lua_touserdata(aState, Index + FirstStructIndex)));
	}

	lua_pushinteger(aState, MsiDetermineApplicablePatches (ProductPackagePath.c_str (), InfoCount, &Infos[0]));

	return 1;
}

int LMsiEnumPatchesEx(lua_State* aState)
{
    String Product = luaL_checkstring(aState, 1);
	String UserSid = luaL_checkstring(aState, 2);
    int Context = luaL_checkint(aState, 3);
    int Filter = luaL_checkint(aState, 4);
    int Index = luaL_checkint(aState, 5);
    _TCHAR PatchCode[MAX_GUID_CHARS + 1] = {0};
    _TCHAR TargetProductCode[MAX_GUID_CHARS + 1] = {0};
    MSIINSTALLCONTEXT ContextOut;
    _TCHAR TargetUserSid[DefaultBuffer] = {0};
    DWORD TargetUserSidLength = DefaultBuffer;

    UINT Check = MsiEnumPatchesEx (Product.c_str (), UserSid.c_str (), Context, Filter, Index, PatchCode, TargetProductCode, &ContextOut, TargetUserSid, &TargetUserSidLength);

    CheckResult (Check, ERROR_SUCCESS, ERROR_NO_MORE_ITEMS);

    if (Check == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushstring(aState, PatchCode);
        lua_pushstring(aState, TargetProductCode);
        lua_pushinteger(aState, ContextOut);
        lua_pushstring(aState, PatchCode);

        return 5;
    }

    lua_pushboolean(aState, false);
    return 1;
}

INSTALLSTATE LMsiQueryFeatureState(
	LPCSTR  szProduct,
	LPCSTR  szFeature)
{
    return MsiQueryFeatureState(szProduct, szFeature);
}

INSTALLSTATE LMsiQueryFeatureStateEx(
	LPCSTR  szProduct,
	LPCSTR szUserSid,
	MSIINSTALLCONTEXT dwContext,
	LPCSTR  szFeature)
{
    INSTALLSTATE State;
    CheckResult(MsiQueryFeatureStateEx(szProduct, szUserSid, dwContext, szFeature, &State), ERROR_SUCCESS);
    return State;
}

INSTALLSTATE LMsiUseFeature(
	LPCSTR  szProduct,
	LPCSTR  szFeature)
{
    return MsiUseFeature(szProduct, szFeature);
}

INSTALLSTATE LMsiUseFeatureEx(
	LPCSTR  szProduct,
	LPCSTR  szFeature,
	DWORD     dwInstallMode)
{
    return MsiUseFeatureEx(szProduct, szFeature, dwInstallMode, 0);
}

int LMsiGetFeatureUsage(lua_State* aState)
{
    String Product = luaL_checkstring (aState, 1);
    String Feature = luaL_checkstring (aState, 2);
    DWORD Count = 0;
    WORD DateUsed = 0;

    CheckResult (MsiGetFeatureUsage (Product.c_str (), Feature.c_str (), &Count, &DateUsed), ERROR_SUCCESS);

    lua_pushinteger(aState, Count);
    lua_pushinteger(aState, DateUsed);

    return 2;
}

UINT LMsiConfigureFeature(
	LPCSTR  szProduct,
	LPCSTR  szFeature,
	INSTALLSTATE eInstallState)
{
    return MsiConfigureFeature(szProduct, szFeature, eInstallState);
}

UINT LMsiReinstallFeature(
	LPCSTR      szProduct,
	LPCSTR      szFeature,
	DWORD         dwReinstallMode)
{
    return MsiReinstallFeature(szProduct, szFeature, dwReinstallMode);
}

 String LMsiProvideComponent(
	LPCSTR     szProduct,
	LPCSTR     szFeature,
	LPCSTR     szComponent,
	DWORD        dwInstallMode)
{
   _TCHAR Buffer[MAX_PATH] = {0};
    DWORD  BufferLength = MAX_PATH;

    CheckResult (MsiProvideComponent(szProduct, szFeature, szComponent, dwInstallMode, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}

String LMsiProvideQualifiedComponent(
	LPCSTR     szCategory,
	LPCSTR     szQualifier,
	DWORD        dwInstallMode)
{
   _TCHAR Buffer[MAX_PATH] = {0};
    DWORD  BufferLength = MAX_PATH;

    CheckResult (MsiProvideQualifiedComponent(szCategory, szQualifier, dwInstallMode, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}

String LMsiProvideQualifiedComponentEx(
	LPCSTR     szCategory,
	LPCSTR     szQualifier,
	DWORD        dwInstallMode,
	LPCSTR     szProduct)
{
   _TCHAR Buffer[MAX_PATH] = {0};
    DWORD  BufferLength = MAX_PATH;

    CheckResult (MsiProvideQualifiedComponentEx(szCategory, szQualifier, dwInstallMode, szProduct, 0, 0, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}

String LMsiGetComponentPath(
	LPCSTR   szProduct,
	LPCSTR   szComponent)
{
    _TCHAR Buffer[MAX_PATH] = {0};
    DWORD  BufferLength = MAX_PATH;

    CheckResult (MsiGetComponentPath (szProduct, szComponent, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}
/*
String LMsiGetComponentPathEx(
	LPCSTR   szProduct,
	LPCSTR   szComponent,
	LPCSTR		szUserSid,
	MSIINSTALLCONTEXT	dwContext)
{
    _TCHAR Buffer[MAX_PATH] = {0};
    DWORD  BufferLength = MAX_PATH;

    CheckResult (MsiGetComponentPathEx (szProduct, szComponent, szUserSid, dwContext, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}
*/
String LMsiProvideAssembly(
	LPCSTR    szAssemblyName,
	LPCSTR    szAppContext,
	DWORD       dwInstallMode,
	DWORD       dwAssemblyInfo)
{
    _TCHAR Buffer[MAX_PATH] = {0};
    DWORD  BufferLength = MAX_PATH;

    CheckResult (MsiProvideAssembly (szAssemblyName, szAppContext, dwInstallMode, dwAssemblyInfo, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}


INSTALLSTATE LMsiQueryComponentState(
		LPCSTR szProductCode,
		LPCSTR szUserSid,
		MSIINSTALLCONTEXT dwContext,
		LPCSTR szComponentCode)
{
    INSTALLSTATE Result;

    CheckResult(MsiQueryComponentState(szProductCode, szUserSid, dwContext, szComponentCode, &Result), ERROR_SUCCESS);

    return Result;
}

int LMsiEnumProducts(lua_State* aState)
{
    DWORD ProductIndex = luaL_checkint(aState, 1);
    _TCHAR Buffer[MAX_GUID_CHARS + 1] = {0};

    if (CheckResult(MsiEnumProducts(ProductIndex, Buffer), ERROR_SUCCESS, ERROR_NO_MORE_ITEMS) == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushstring(aState, Buffer);
        return 2;
    }

    lua_pushboolean(aState, false);
    return 1;
}

int LMsiEnumProductsEx(lua_State* aState)
{
    String ProductCode = luaL_checkstring (aState, 1);
    String UserSid = luaL_checkstring (aState, 2);
    DWORD Context = luaL_checkint (aState, 3);
    DWORD Index = luaL_checkint (aState, 4);
    _TCHAR InstalledProductCode[MAX_GUID_CHARS + 1] = {0};
    MSIINSTALLCONTEXT InstalledContext;
    _TCHAR Sid[DefaultBuffer] = {0};
    DWORD SidLength = DefaultBuffer;

    UINT Check = MsiEnumProductsEx(ProductCode.c_str (), UserSid.c_str (), Context, Index, InstalledProductCode, &InstalledContext, Sid, &SidLength);

    CheckResult(Check, ERROR_SUCCESS, ERROR_NO_MORE_ITEMS);

    if (Check == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushstring(aState, InstalledProductCode);
        lua_pushinteger(aState, InstalledContext);
        lua_pushstring(aState, Sid);

        return 4;
    }

    lua_pushboolean(aState, false);
    return 1;
}

int LMsiEnumRelatedProducts(lua_State* aState)
{
    String UpgradeCode = luaL_checkstring (aState, 1);
    DWORD Index = luaL_checkint (aState, 2);
    _TCHAR ProductCode[MAX_GUID_CHARS + 1] = {0};

    if (CheckResult(MsiEnumRelatedProducts(UpgradeCode.c_str (), 0, Index, ProductCode), ERROR_SUCCESS, ERROR_NO_MORE_ITEMS) == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushstring(aState, ProductCode);

        return 2;
    }

    lua_pushboolean(aState, false);
    return 1;
}

int LMsiEnumFeatures(lua_State* aState)
{
    String ProductCode = luaL_checkstring (aState, 1);
    DWORD Index = luaL_checkint (aState, 2);
    _TCHAR Feature[MAX_GUID_CHARS + 1] = {0};
    _TCHAR ParentFeature[MAX_GUID_CHARS + 1] = {0};

    if (CheckResult(MsiEnumFeatures(ProductCode.c_str (), Index, Feature, ParentFeature), ERROR_SUCCESS, ERROR_NO_MORE_ITEMS) == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushstring(aState, Feature);
        lua_pushstring(aState, ParentFeature);

        return 3;
    }

    lua_pushboolean(aState, false);
    return 1;
}

int LMsiEnumClients(lua_State* aState)
{
    String Component = luaL_checkstring(aState, 1);
    DWORD Index = luaL_checkint(aState, 2);
    _TCHAR Buffer[MAX_GUID_CHARS + 1] = {0};

    if (CheckResult(MsiEnumClients(Component.c_str (), Index, Buffer), ERROR_SUCCESS, ERROR_NO_MORE_ITEMS) == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushstring(aState, Buffer);
        return 2;
    }

    lua_pushboolean(aState, false);
    return 1;
}

int LMsiEnumComponents(lua_State* aState)
{
    DWORD Index = luaL_checkint(aState, 1);
    _TCHAR Buffer[MAX_GUID_CHARS + 1] = {0};

    if (CheckResult(MsiEnumComponents(Index, Buffer), ERROR_SUCCESS, ERROR_NO_MORE_ITEMS) == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushstring(aState, Buffer);
        return 2;
    }

    lua_pushboolean(aState, false);
    return 1;
}
/*
int LMsiEnumComponentsEx(lua_State* aState)
{
    String User = luaL_checkstring(aState, 1);
    DWORD Context = luaL_checkint(aState, 2);
    DWORD Index = luaL_checkint(aState, 2);
    _TCHAR InstalledComponentCode[MAX_GUID_CHARS + 1] = {0};
    MSIINSTALLCONTEXT	InstalledContext;
    _TCHAR Sid[DefaultBuffer] = {0};
    DWORD SidLength = DefaultBuffer;

    if (CheckResult(MsiEnumComponentsEx(User.c_str (), Context, Index, InstalledComponentCode, &InstalledContext, Sid, &SidLength), ERROR_SUCCESS, ERROR_NO_MORE_ITEMS) == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushstring(aState, InstalledComponentCode);
        lua_pushinteger(aState, InstalledContext);
        lua_pushstring(aState, Sid);

        return 4;
    }

    lua_pushboolean(aState, false);
    return 1;
}

int LMsiEnumClientsEx(lua_State* aState)
{
    /*
    String Component = luaL_checkstring(aState, 1);
    String User = luaL_checkstring(aState, 2);
    DWORD Context = luaL_checkint(aState, 3);
    DWORD Index = luaL_checkint(aState, 4);
    _TCHAR Product[MAX_GUID_CHARS + 1] = {0};
    MSIINSTALLCONTEXT	InstalledContext;
    _TCHAR Sid[DefaultBuffer] = {0};
    DWORD SidLength = DefaultBuffer;

    if (CheckResult(MsiEnumClientsEx(Component.c_str (), User.c_str (), Context, Index, Product, &InstalledContext, Sid, &SidLength), ERROR_SUCCESS, ERROR_NO_MORE_ITEMS) == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushstring(aState, Product);
        lua_pushinteger(aState, InstalledContext);
        lua_pushstring(aState, Sid);

        return 4;
    }

    lua_pushboolean(aState, false);
    return 1;
}
*/
int LMsiEnumComponentQualifiers(lua_State* aState)
{
    String Component = luaL_checkstring(aState, 1);
    DWORD Index = luaL_checkint(aState, 2);
    _TCHAR Qualifier[DefaultBuffer] = {0};
    DWORD QualifierLength = DefaultBuffer;
    _TCHAR ApplicationData[DefaultBuffer] = {0};
    DWORD ApplicationDataLength = DefaultBuffer;

    if (CheckResult(MsiEnumComponentQualifiers(Component.c_str (), Index, Qualifier, &QualifierLength, ApplicationData, &ApplicationDataLength), ERROR_SUCCESS, ERROR_NO_MORE_ITEMS) == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushstring(aState, Qualifier);
        lua_pushstring(aState, ApplicationData);

        return 3;
    }

    lua_pushboolean(aState, false);
    return 1;
}

MSIHANDLE LMsiOpenProduct(
	LPCSTR    szProduct
	)
{
    MSIHANDLE Result;
    CheckResult(MsiOpenProduct (szProduct, &Result), ERROR_SUCCESS);

    return Result;
}

MSIHANDLE LMsiOpenPackage(
	LPCSTR    szPackagePath
	)
{
    MSIHANDLE Result;
    CheckResult(MsiOpenPackage (szPackagePath, &Result), ERROR_SUCCESS);

    return Result;
}

MSIHANDLE LMsiOpenPackageEx(
	LPCSTR    szPackagePath,
	DWORD     dwOptions
	)
{
    MSIHANDLE Result;
    CheckResult(MsiOpenPackageEx (szPackagePath, dwOptions, &Result), ERROR_SUCCESS);

    return Result;
}

int LMsiGetPatchFileList(lua_State* aState)
{
    String ProductCode = luaL_checkstring(aState, 1);
    String PatchList = luaL_checkstring(aState, 2);
    DWORD Count = 0;
    MSIHANDLE* List = 0;

    CheckResult(MsiGetPatchFileList (ProductCode.c_str (), PatchList.c_str (), &Count, &List), ERROR_SUCCESS);

    for (DWORD Index = 0; Index < Count; ++Index) {
        lua_pushinteger(aState, List[Index]);
    }

    return Count;
}

String LMsiGetPatchFileListMsiGetProductProperty(
	MSIHANDLE   hProduct,
	LPCSTR    szProperty)
{
    _TCHAR Buffer[DefaultBuffer] = {0};
    DWORD BufferLength = DefaultBuffer;

    CheckResult (MsiGetProductProperty (hProduct, szProperty, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}

UINT LMsiVerifyPackage(LPCSTR      szPackagePath)
{
    return CheckResult(MsiVerifyPackage (szPackagePath), ERROR_SUCCESS, ERROR_INSTALL_PACKAGE_INVALID);
}

int LMsiGetFeatureInfo(lua_State* aState)
{
    MSIHANDLE Product = luaL_checkint(aState, 1);
    String Feature = luaL_checkstring(aState, 2);
    DWORD Attributes = 0;
    _TCHAR Title[DefaultBuffer] = {0};
    DWORD TitleLength = 0;
    _TCHAR Help[DefaultBuffer] = {0};
    DWORD HelpLength = 0;

    CheckResult (MsiGetFeatureInfo (Product, Feature.c_str (), &Attributes, Title, &TitleLength, Help, &HelpLength), ERROR_SUCCESS);

    lua_pushinteger(aState, Attributes);
    lua_pushstring(aState, Title);
    lua_pushstring(aState, Help);

    return 3;
}

UINT LMsiInstallMissingComponent(
	LPCSTR      szProduct,
	LPCSTR      szComponent,
	INSTALLSTATE eInstallState)
{
    return CheckResult (MsiInstallMissingComponent(szProduct, szComponent, eInstallState), ERROR_SUCCESS, ERROR_INSTALL_USEREXIT);
}

UINT LMsiInstallMissingFile(
	LPCSTR      szProduct,
	LPCSTR      szFile)
{
    return CheckResult (MsiInstallMissingFile(szProduct, szFile), ERROR_SUCCESS, ERROR_INSTALL_USEREXIT);
}

int LMsiLocateComponent(lua_State* aState)
{
    String Component = luaL_checkstring(aState, 1);
    _TCHAR Buffer[DefaultBuffer] = {0};
    DWORD BufferLength = DefaultBuffer;

    INSTALLSTATE Result = MsiLocateComponent(Component.c_str (), Buffer, &BufferLength);
    CheckResult (Result, INSTALLSTATE_NOTUSED, INSTALLSTATE_ABSENT, INSTALLSTATE_LOCAL, INSTALLSTATE_SOURCE);

    lua_pushinteger(aState, Result);

    if (BufferLength) {
        lua_pushstring(aState, Buffer);
        return 2;
    }

    return 1;
}

void LMsiSourceListClearAll(
	LPCSTR szProduct,
	LPCSTR szUserName)
{
    CheckResult(MsiSourceListClearAll(szProduct, szUserName, 0), ERROR_SUCCESS);
}

void LMsiSourceListAddSource(
	LPCSTR szProduct,
	LPCSTR szUserName,
	LPCSTR szSource)
{
    CheckResult(MsiSourceListAddSource(szProduct, szUserName, 0, szSource), ERROR_SUCCESS);
}

void LMsiSourceListForceResolution(
	LPCSTR szProduct,
	LPCSTR szUserName)
{
    CheckResult(MsiSourceListForceResolution(szProduct, szUserName, 0), ERROR_SUCCESS);
}

void LMsiSourceListAddSourceEx(
	LPCSTR szProductCodeOrPatchCode,
	LPCSTR szUserSid,
	MSIINSTALLCONTEXT dwContext,
	DWORD dwOptions,
	LPCSTR szSource,
	DWORD dwIndex)
{
    CheckResult(MsiSourceListAddSourceEx(szProductCodeOrPatchCode, szUserSid, dwContext, dwOptions, szSource, dwIndex), ERROR_SUCCESS);
}

void LMsiSourceListAddMediaDisk(
	LPCSTR szProductCodeOrPatchCode,
	LPCSTR szUserSid,
	MSIINSTALLCONTEXT dwContext,
	DWORD dwOptions,
	DWORD dwDiskId,
	LPCSTR szVolumeLabel,
	LPCSTR szDiskPrompt)
{
    CheckResult(MsiSourceListAddMediaDisk(szProductCodeOrPatchCode, szUserSid, dwContext, dwOptions, dwDiskId, szVolumeLabel, szDiskPrompt), ERROR_SUCCESS);
}

void LMsiSourceListClearSource(
	LPCSTR szProductCodeOrPatchCode,
	LPCSTR szUserSid,
	MSIINSTALLCONTEXT dwContext,
	DWORD dwOptions,
	LPCSTR szSource)
{
    CheckResult(MsiSourceListClearSource(szProductCodeOrPatchCode, szUserSid, dwContext, dwOptions, szSource), ERROR_SUCCESS);
}

void LMsiSourceListClearMediaDisk(
	LPCSTR szProductCodeOrPatchCode,
	LPCSTR szUserSid,
	MSIINSTALLCONTEXT dwContext,
	DWORD dwOptions,
	DWORD dwDiskId)
{
    CheckResult(MsiSourceListClearMediaDisk(szProductCodeOrPatchCode, szUserSid, dwContext, dwOptions, dwDiskId), ERROR_SUCCESS);
}

void LMsiSourceListClearAllEx(
	LPCSTR szProductCodeOrPatchCode,
	LPCSTR szUserSid,
	MSIINSTALLCONTEXT dwContext,
	DWORD dwOptions)
{
    CheckResult(MsiSourceListClearAllEx(szProductCodeOrPatchCode, szUserSid, dwContext, dwOptions), ERROR_SUCCESS);
}

void LMsiSourceListForceResolutionEx(
	LPCSTR szProductCodeOrPatchCode,
	LPCSTR szUserSid,
	MSIINSTALLCONTEXT dwContext,
	DWORD dwOptions)
{
    CheckResult(MsiSourceListForceResolutionEx(szProductCodeOrPatchCode, szUserSid, dwContext, dwOptions), ERROR_SUCCESS);
}

void LMsiSourceListSetInfo(
	LPCSTR szProductCodeOrPatchCode,
	LPCSTR szUserSid,
	MSIINSTALLCONTEXT dwContext,
	DWORD dwOptions,
	LPCSTR szProperty,
	LPCSTR szValue)
{
    CheckResult(MsiSourceListSetInfo(szProductCodeOrPatchCode, szUserSid, dwContext, dwOptions, szProperty, szValue), ERROR_SUCCESS);
}

String LMsiSourceListGetInfo(
	LPCSTR szProductCodeOrPatchCode,
	LPCSTR szUserSid,
	MSIINSTALLCONTEXT dwContext,
	DWORD dwOptions,
	LPCSTR szProperty)
{
    _TCHAR Buffer[DefaultBuffer] = {0};
    DWORD BufferLength = DefaultBuffer;

    CheckResult(MsiSourceListGetInfo(szProductCodeOrPatchCode, szUserSid, dwContext, dwOptions, szProperty, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}

int LMsiSourceListEnumSources(lua_State* aState)
{
    String ProductCodeOrPatchCode = luaL_checkstring(aState, 1);
    String UserSid = luaL_checkstring(aState, 2);
    MSIINSTALLCONTEXT Context = (MSIINSTALLCONTEXT)luaL_checkint(aState, 3);
    DWORD Options = (DWORD)luaL_checkint(aState, 4);
    DWORD Index = (DWORD)luaL_checkint(aState, 5);
    _TCHAR Buffer[DefaultBuffer] = {0};
    DWORD BufferLength = DefaultBuffer;

    if (CheckResult(MsiSourceListEnumSources(ProductCodeOrPatchCode.c_str (), UserSid.c_str (), Context, Options, Index, Buffer, &BufferLength), ERROR_SUCCESS, ERROR_NO_MORE_ITEMS) == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushstring(aState, Buffer);

        return 2;
    }

    lua_pushboolean(aState, false);

    return 1;
}

int LMsiSourceListEnumMediaDisks(lua_State* aState)
{
    String ProductCodeOrPatchCode = luaL_checkstring(aState, 1);
    String UserSid = luaL_checkstring(aState, 2);
    MSIINSTALLCONTEXT Context = (MSIINSTALLCONTEXT)luaL_checkint(aState, 3);
    DWORD Options = (DWORD)luaL_checkint(aState, 4);
    DWORD Index = (DWORD)luaL_checkint(aState, 5);
    DWORD DiskId = 0;
    _TCHAR VolumeLabel[DefaultBuffer] = {0};
    DWORD VolumeLabelLength = DefaultBuffer;
    _TCHAR DiskPrompt[DefaultBuffer] = {0};
    DWORD DiskPromptLength = DefaultBuffer;

    if (CheckResult(MsiSourceListEnumMediaDisks(ProductCodeOrPatchCode.c_str (), UserSid.c_str (), Context, Options, Index, &DiskId, VolumeLabel, &VolumeLabelLength, DiskPrompt, &DiskPromptLength), ERROR_SUCCESS, ERROR_NO_MORE_ITEMS) == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushinteger(aState, DiskId);
        lua_pushstring(aState, VolumeLabel);
        lua_pushstring(aState, DiskPrompt);

        return 4;
    }

    lua_pushboolean(aState, false);

    return 1;
}

int LMsiGetFileVersion(lua_State* aState)
{
    String FilePath = luaL_checkstring(aState, 1);
    _TCHAR Version[DefaultBuffer] = {0};
    DWORD VersionLength = DefaultBuffer;
    _TCHAR Language[DefaultBuffer] = {0};
    DWORD LanguageLength = DefaultBuffer;

    CheckResult(MsiGetFileVersion(FilePath.c_str(), Version, &VersionLength, Language, &LanguageLength), ERROR_SUCCESS);

    lua_pushstring(aState, Version);
    lua_pushstring(aState, Language);

    return 2;
}

bool LMsiIsProductElevated(
	LPCSTR szProduct)
{
    BOOL Result;
    CheckResult(MsiIsProductElevated(szProduct, &Result), ERROR_SUCCESS);

    return Result != 0;
}

void LMsiNotifySidChange(LPCSTR pOldSid, LPCSTR pNewSid)
{
    CheckResult(MsiNotifySidChange(pOldSid, pNewSid), ERROR_SUCCESS);
}

int LMsiGetShortcutTarget(lua_State* aState)
{
    String ShortcutPath = luaL_checkstring(aState, 1);
	_TCHAR ProductCode[MAX_GUID_CHARS + 1] = {0};
	_TCHAR FeatureId[MAX_FEATURE_CHARS + 1] = {0};
	_TCHAR ComponentCode[MAX_GUID_CHARS + 1] = {0};

	CheckResult(MsiGetShortcutTarget(ShortcutPath.c_str(), ProductCode, FeatureId, ComponentCode), ERROR_SUCCESS);

	lua_pushstring(aState, ProductCode);
	lua_pushstring(aState, FeatureId);
	lua_pushstring(aState, ComponentCode);

	return 3;
}

int LMsiGetFileHash(lua_State* aState)
{
    String FilePath = luaL_checkstring(aState, 1);
    DWORD Options = luaL_checkint(aState, 2);
    MSIFILEHASHINFO Hash;

	CheckResult(MsiGetFileHash(FilePath.c_str(), Options, &Hash), ERROR_SUCCESS);

	push(aState, Hash);
	return 1;
}

int LMsiGetFileSignatureInformation(lua_State* aState)
{
    String SignedObjectPath = luaL_checkstring(aState, 1);
    DWORD Flags = luaL_checkint(aState, 2);
    PCCERT_CONTEXT Context = 0;
    BYTE HashData[DefaultBuffer * 4] = {0};
    DWORD HashDataLength = DefaultBuffer * 4;

    if (CheckResult(MsiGetFileSignatureInformation(SignedObjectPath.c_str(), Flags, &Context, HashData, &HashDataLength), ERROR_SUCCESS, TRUST_E_NOSIGNATURE) == ERROR_SUCCESS) {
        lua_pushboolean(aState, true);
        lua_pushlightuserdata(aState, (void*)Context);

        return 2;
    }

    lua_pushboolean(aState, false);
    return 1;
}

int LMsiBeginTransaction(lua_State* aState)
{
    String Name = luaL_checkstring(aState, 1);
    DWORD TransactionAttributes = luaL_checkint(aState, 2);
    MSIHANDLE Transaction;
    HANDLE OwnerChanged;

    CheckResult(MsiBeginTransaction(Name.c_str(), TransactionAttributes, &Transaction, &OwnerChanged), ERROR_SUCCESS);

    lua_pushinteger(aState, Transaction);
    lua_pushlightuserdata(aState, OwnerChanged);

    return 2;
}

void LMsiEndTransaction(
	DWORD dwTransactionState)
{
    CheckResult(MsiEndTransaction(dwTransactionState), ERROR_SUCCESS);
}

HANDLE LMsiJoinTransaction(
	MSIHANDLE hTransactionHandle,
	DWORD dwTransactionAttributes)
{
    HANDLE Result;

    CheckResult(MsiJoinTransaction(hTransactionHandle, dwTransactionAttributes, &Result), ERROR_SUCCESS);

    return Result;
}

MSIHANDLE LMsiDatabaseOpenView(MSIHANDLE hDatabase,
	LPCSTR     szQuery)
{
    MSIHANDLE Result;

    CheckResult(MsiDatabaseOpenView(hDatabase, szQuery, &Result), ERROR_SUCCESS);

    return Result;
}

int LMsiViewGetError(lua_State* aState)
{
    MSIHANDLE View = luaL_checkint(aState, 1);
    _TCHAR Buffer[DefaultBuffer] = {0};
    DWORD BufferLength = DefaultBuffer;

    MSIDBERROR Error = MsiViewGetError(View, Buffer, &BufferLength);

	lua_pushinteger(aState, Error);
	lua_pushstring(aState, Buffer);

	return 2;
}

void LMsiViewExecute(MSIHANDLE hView,
	MSIHANDLE hRecord)
{
    CheckResult(MsiViewExecute(hView, hRecord), ERROR_SUCCESS);
}

MSIHANDLE LMsiViewFetch(MSIHANDLE hView)
{
    MSIHANDLE Result;
    CheckResult(MsiViewFetch(hView, &Result), ERROR_SUCCESS, ERROR_NO_MORE_ITEMS);

    return Result;
}

void LMsiViewModify(MSIHANDLE hView,
	MSIMODIFY eModifyMode,
	MSIHANDLE hRecord)
{
    CheckResult(MsiViewModify(hView, eModifyMode, hRecord), ERROR_SUCCESS);
}

MSIHANDLE LMsiViewGetColumnInfo(MSIHANDLE hView,
	MSICOLINFO eColumnInfo)
{
    MSIHANDLE Result;

    CheckResult(MsiViewGetColumnInfo(hView, eColumnInfo, &Result), ERROR_SUCCESS);

    return Result;
}

void LMsiViewClose(MSIHANDLE hView)
{
    CheckResult(MsiViewClose(hView), ERROR_SUCCESS);
}

MSIHANDLE LMsiDatabaseGetPrimaryKeys(MSIHANDLE hDatabase,
	LPCSTR    szTableName)
{
    MSIHANDLE Result;

    CheckResult(MsiDatabaseGetPrimaryKeys(hDatabase, szTableName, &Result), ERROR_SUCCESS);

    return Result;
}

MSICONDITION LMsiDatabaseIsTablePersistent(MSIHANDLE hDatabase,
	LPCSTR szTableName)
{
    return CheckResult(MsiDatabaseIsTablePersistentA(hDatabase, szTableName), MSICONDITION_TRUE, MSICONDITION_FALSE);
}

MSIHANDLE LMsiGetSummaryInformation(MSIHANDLE hDatabase,
	LPCSTR  szDatabasePath,
	UINT     uiUpdateCount)
{
    MSIHANDLE Result;

    CheckResult(MsiGetSummaryInformation(hDatabase, szDatabasePath, uiUpdateCount, &Result), ERROR_SUCCESS);

    return Result;
}

UINT LMsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo)
{
    UINT Result;

    CheckResult(MsiSummaryInfoGetPropertyCount(hSummaryInfo, &Result), ERROR_SUCCESS);

    return Result;
}

int LMsiSummaryInfoSetProperty(lua_State* aState)
{
    MSIHANDLE Handle = (MSIHANDLE)luaL_checkint(aState, 1);
    UINT Property = (UINT)luaL_checkint(aState, 2);
    UINT DataType = 0;
    int Value = 0;
    FILETIME Time;
    LPCSTR Text = 0;

    switch (lua_type(aState, 4)) {
    case LUA_TNIL:
        DataType = VT_EMPTY;
        break;
    case LUA_TNUMBER:
        DataType = VT_I4;
        Value = lua_tointeger(aState, 4);
        break;
    case LUA_TSTRING:
        DataType = VT_LPSTR;
        Text = lua_tostring(aState, 4);
        break;
    case LUA_TUSERDATA:
    case LUA_TLIGHTUSERDATA:
        DataType = VT_FILETIME;
        Time = *((FILETIME*)lua_touserdata(aState, 4));
        break;
    default:
        luaL_error(aState, "SummaryInfoSetProperty - unhandled datatype");
        break;
    }

    CheckResult(MsiSummaryInfoSetProperty(Handle, Property, DataType, Value, &Time, Text), ERROR_SUCCESS);

    return 0;
}

int LMsiSummaryInfoGetProperty(lua_State* aState)
{
    MSIHANDLE Summary = (MSIHANDLE)luaL_checkint(aState, 1);
    UINT Property = (UINT)luaL_checkint(aState, 2);
    UINT DataType;
    INT Value;
    FILETIME Time;
    _TCHAR Buffer[DefaultBuffer] = {0};
    DWORD BufferLength = DefaultBuffer;

    CheckResult(MsiSummaryInfoGetProperty(Summary, Property, &DataType, &Value, &Time, Buffer, &BufferLength), ERROR_SUCCESS);

    switch (DataType) {
    case VT_I4:
        lua_pushinteger(aState, Value);
        break;
    case VT_LPSTR:
        lua_pushstring(aState, Buffer);
        break;
    case VT_FILETIME:
        push(aState, Time);
        break;
    default:
        lua_pushnil(aState);
        break;
    }

    return 1;
}

void LMsiSummaryInfoPersist(MSIHANDLE hSummaryInfo)
{
    CheckResult(MsiSummaryInfoPersist(hSummaryInfo), ERROR_SUCCESS);
}

MSIHANDLE LMsiOpenDatabase(
	LPCSTR      szDatabasePath,
	LPCSTR      szPersist)
{
    MSIHANDLE Result;

    CheckResult(MsiOpenDatabase(szDatabasePath, szPersist, &Result), ERROR_SUCCESS);

    return Result;
}

void LMsiDatabaseImport(MSIHANDLE hDatabase,
	LPCSTR   szFolderPath,
	LPCSTR   szFileName)
{
    CheckResult(MsiDatabaseImport(hDatabase, szFolderPath, szFileName), ERROR_SUCCESS);
}

void LMsiDatabaseExport(MSIHANDLE hDatabase,
	LPCSTR   szTableName,
	LPCSTR   szFolderPath,
	LPCSTR   szFileName)
{
    CheckResult(MsiDatabaseExport(hDatabase, szTableName, szFolderPath, szFileName), ERROR_SUCCESS);
}

void LMsiDatabaseMerge(MSIHANDLE hDatabase,
	MSIHANDLE hDatabaseMerge,
	LPCSTR   szTableName)
{
    CheckResult(MsiDatabaseMerge(hDatabase, hDatabaseMerge, szTableName), ERROR_SUCCESS);
}

void LMsiDatabaseGenerateTransform(MSIHANDLE hDatabase,
	MSIHANDLE hDatabaseReference,
	LPCSTR   szTransformFile)
{
    CheckResult(MsiDatabaseGenerateTransform(hDatabase, hDatabaseReference, szTransformFile, 0, 0), ERROR_SUCCESS);
}

void LMsiDatabaseApplyTransform(MSIHANDLE hDatabase,
	LPCSTR   szTransformFile,
	int       iErrorConditions)
{
    CheckResult(MsiDatabaseApplyTransform(hDatabase, szTransformFile, iErrorConditions), ERROR_SUCCESS);
}

void LMsiCreateTransformSummaryInfo(MSIHANDLE hDatabase,
	MSIHANDLE hDatabaseReference,
	LPCSTR   szTransformFile,
	int       iErrorConditions,
	int       iValidation)
{
    CheckResult(MsiCreateTransformSummaryInfo(hDatabase, hDatabaseReference, szTransformFile, iErrorConditions, iValidation), ERROR_SUCCESS);
}

void LMsiDatabaseCommit(MSIHANDLE hDatabase)
{
    CheckResult(MsiDatabaseCommit(hDatabase), ERROR_SUCCESS);
}

MSIHANDLE LMsiCreateRecord(
	UINT cParams)
{
    return MsiCreateRecord(cParams);
}

BOOL LMsiRecordIsNull(MSIHANDLE hRecord,
	UINT iField)
{
    return MsiRecordIsNull(hRecord, iField);
}

UINT LMsiRecordDataSize(MSIHANDLE hRecord,
	UINT iField)
{
    return MsiRecordDataSize(hRecord, iField);
}

int LMsiRecordGetInteger(MSIHANDLE hRecord,
	UINT iField)
{
    return MsiRecordGetInteger(hRecord, iField);
}

UINT LMsiRecordGetFieldCount(MSIHANDLE hRecord)
{
    return MsiRecordGetFieldCount(hRecord);
}

MSIDBSTATE LMsiGetDatabaseState(MSIHANDLE hDatabase)
{
    return (MSIDBSTATE)CheckResult(MsiGetDatabaseState(hDatabase), Msidbstate::Read, Msidbstate::Write);
}

void LMsiRecordSetString(MSIHANDLE hRecord,
	UINT iField,
	LPCSTR      szValue)
{
    CheckResult(MsiRecordSetString(hRecord, iField, szValue), ERROR_SUCCESS);
}

String LMsiRecordGetString(MSIHANDLE hRecord,
	                                UINT iField)
{
    _TCHAR Buffer[DefaultBuffer] = {0};
    DWORD BufferLength = DefaultBuffer;

    CheckResult(MsiRecordGetString(hRecord, iField, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}

void LMsiRecordSetStream(MSIHANDLE hRecord,
	UINT iField,
	LPCSTR      szFileName)
{
    CheckResult(MsiRecordSetStream(hRecord, iField, szFileName), ERROR_SUCCESS);
}

String LMsiRecordReadStream(MSIHANDLE hRecord,
	                                UINT iField)
{
    String Result;
    DWORD BufferLength = 0;

    if (CheckResult(MsiRecordReadStream(hRecord, iField, 0, &BufferLength), ERROR_SUCCESS, ERROR_MORE_DATA)) {
        Result.resize(++BufferLength);
        CheckResult(MsiRecordReadStream(hRecord, iField, &Result[0], &BufferLength), ERROR_SUCCESS);
    }

    return Result;
}

void LMsiRecordClearData(MSIHANDLE hRecord)
{
    CheckResult(MsiRecordClearData(hRecord), ERROR_SUCCESS);
}

MSIHANDLE LMsiGetActiveDatabase(MSIHANDLE hInstall)
{
    return MsiGetActiveDatabase(hInstall);
}

void LMsiSetProperty(MSIHANDLE hInstall,
	LPCSTR   szName,
	LPCSTR   szValue)
{
    CheckResult(MsiSetProperty(hInstall, szName, szValue), ERROR_SUCCESS);
}

String LMsiGetProperty(MSIHANDLE hInstall,
	                                 LPCSTR szName)
{
    _TCHAR Buffer[DefaultBuffer] = {0};
    DWORD BufferLength = DefaultBuffer;

    CheckResult(MsiGetProperty(hInstall, szName, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}

LANGID LMsiGetLanguage(MSIHANDLE hInstall)
{
    return MsiGetLanguage(hInstall);
}

bool LMsiGetMode(MSIHANDLE hInstall,
	MSIRUNMODE eRunMode)
{
    return MsiGetMode(hInstall, eRunMode) != 0;
}

void LMsiSetMode(MSIHANDLE hInstall,
	MSIRUNMODE eRunMode,
	BOOL fState)
{
    CheckResult(MsiSetMode(hInstall, eRunMode, fState), ERROR_SUCCESS);
}

String LMsiFormatRecord(MSIHANDLE hInstall,
	                                  MSIHANDLE hRecord)
{
    _TCHAR Buffer[DefaultBuffer] = {0};
    DWORD BufferLength = DefaultBuffer;

    CheckResult(MsiFormatRecord(hInstall, hRecord, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}

UINT LMsiDoAction(MSIHANDLE hInstall,
	LPCSTR szAction)
{
    return CheckResult(MsiDoAction(hInstall, szAction), ERROR_SUCCESS, ERROR_INSTALL_USEREXIT, ERROR_MORE_DATA);
}

void LMsiSequence(MSIHANDLE hInstall,
	LPCSTR szTable,
	INT iSequenceMode)
{
    CheckResult(MsiSequence(hInstall, szTable, iSequenceMode), ERROR_SUCCESS);
}

int LMsiProcessMessage(MSIHANDLE hInstall,
	INSTALLMESSAGE eMessageType,
	MSIHANDLE hRecord)
{
    return MsiProcessMessage(hInstall, eMessageType, hRecord);
}

MSICONDITION LMsiEvaluateCondition(MSIHANDLE hInstall,
	LPCSTR  szCondition)
{
    return MsiEvaluateCondition(hInstall, szCondition);
}

int LMsiGetFeatureState(lua_State* aState)
{
    MSIHANDLE Install = (MSIHANDLE)luaL_checkint(aState, 1);
    String Feature = luaL_checkstring(aState, 2);
    INSTALLSTATE Installed;
    INSTALLSTATE Action;

    CheckResult(MsiGetFeatureState(Install, Feature.c_str(), &Installed, &Action), ERROR_SUCCESS);

    lua_pushinteger(aState, Installed);
    lua_pushinteger(aState, Action);

    return 2;
}

void LMsiSetFeatureState(MSIHANDLE hInstall,
	LPCSTR     szFeature,
	INSTALLSTATE iState)
{
    CheckResult(MsiSetFeatureState(hInstall, szFeature, iState), ERROR_SUCCESS);
}

void LMsiSetFeatureAttributes(MSIHANDLE hInstall,
	LPCSTR     szFeature,
	DWORD dwAttributes)
{
    CheckResult(MsiSetFeatureAttributes(hInstall, szFeature, dwAttributes), ERROR_SUCCESS);
}

int LMsiGetComponentState(lua_State* aState)
{
    MSIHANDLE Install = (MSIHANDLE)luaL_checkint(aState, 1);
    String Component = luaL_checkstring(aState, 2);
    INSTALLSTATE Installed;
    INSTALLSTATE Action;

    CheckResult(MsiGetComponentState(Install, Component.c_str(), &Installed, &Action), ERROR_SUCCESS);

    lua_pushinteger(aState, Installed);
    lua_pushinteger(aState, Action);

    return 2;
}

void LMsiSetComponentState(MSIHANDLE hInstall,
	LPCSTR     szComponent,
	INSTALLSTATE iState)
{
    CheckResult(MsiSetComponentState(hInstall, szComponent, iState), ERROR_SUCCESS);
}

INT LMsiGetFeatureCost(MSIHANDLE hInstall,
	LPCSTR      szFeature,
	MSICOSTTREE  iCostTree,
	INSTALLSTATE iState)
{
    INT Result;
    CheckResult(MsiGetFeatureCost(hInstall, szFeature, iCostTree, iState, &Result), ERROR_SUCCESS);

    return Result;
}

void LMsiSetInstallLevel(MSIHANDLE hInstall,
	int iInstallLevel)
{
    CheckResult(MsiSetInstallLevel(hInstall, iInstallLevel), ERROR_SUCCESS);
}

UINT LMsiVerifyDiskSpace(MSIHANDLE hInstall)
{
    return CheckResult(MsiVerifyDiskSpace(hInstall), ERROR_DISK_FULL, ERROR_SUCCESS);
}

DWORD LMsiGetFeatureValidStates(MSIHANDLE hInstall,
	LPCSTR szFeature)
{
    DWORD Result;
    CheckResult(MsiGetFeatureValidStates(hInstall, szFeature, &Result), ERROR_SUCCESS);

    return Result;
}

int LMsiEnumComponentCosts(lua_State* aState)
{
    MSIHANDLE Install = (MSIHANDLE)luaL_checkint(aState, 1);
    String Component = luaL_checkstring(aState, 2);
    DWORD Index = luaL_checkint(aState, 3);
    INSTALLSTATE State = (INSTALLSTATE)luaL_checkint(aState, 4);
    _TCHAR Buffer[DefaultBuffer] = {0};
    DWORD BufferLength = DefaultBuffer;
    INT Cost;
    INT TempCost;

    if (CheckResult(MsiEnumComponentCosts(Install, Component.c_str(), Index, State, Buffer, &BufferLength, &Cost, &TempCost), ERROR_SUCCESS, ERROR_NO_MORE_ITEMS)) {
        lua_pushboolean(aState, true);
        lua_pushstring(aState, Buffer);
        lua_pushinteger(aState, Cost);
        lua_pushinteger(aState, TempCost);

        return 4;
    }

    lua_pushboolean(aState, false);
    return 1;
}

String LMsiGetSourcePath(MSIHANDLE hInstall,
	                                LPCSTR     szFolder)
{
    _TCHAR Buffer[DefaultBuffer] = {0};
    DWORD BufferLength = DefaultBuffer;

    CheckResult(MsiGetSourcePath(hInstall, szFolder, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}

String LMsiGetTargetPath(MSIHANDLE hInstall,
	                                LPCSTR     szFolder)
{
    _TCHAR Buffer[DefaultBuffer] = {0};
    DWORD BufferLength = DefaultBuffer;

    CheckResult(MsiGetTargetPath(hInstall, szFolder, Buffer, &BufferLength), ERROR_SUCCESS);

    return Buffer;
}

void LMsiSetTargetPath(MSIHANDLE hInstall,
	LPCSTR     szFolder,
	LPCSTR     szFolderPath)
{
    CheckResult(MsiSetTargetPath(hInstall, szFolder, szFolderPath), ERROR_SUCCESS);
}

MSIHANDLE LMsiGetLastErrorRecord()
{
    return MsiGetLastErrorRecord();
}

MSIHANDLE LMsiEnableUIPreview(MSIHANDLE hDatabase)
{
    MSIHANDLE Result;

    CheckResult(MsiEnableUIPreview(hDatabase, &Result), ERROR_SUCCESS);

    return Result;
}

void LMsiPreviewDialog(MSIHANDLE hPreview,
	LPCSTR szDialogName)
{
    CheckResult(MsiPreviewDialog(hPreview, szDialogName), ERROR_SUCCESS);
}

void LMsiPreviewBillboardA(MSIHANDLE hPreview,
	LPCSTR szControlName,
	LPCSTR szBillboard)
{
    CheckResult(MsiPreviewBillboard(hPreview, szControlName, szBillboard), ERROR_SUCCESS);
}

}

void InitializeMsiBinding(lua_State* aState)
{
    Interpreter = aState;

    getGlobalNamespace (aState)
        .beginNamespace ("Msi")
            .beginNamespace ("InstallMessage")
                .addVariable("Fatalexit", &Installmessage::Fatalexit, false)
                .addVariable("Error", &Installmessage::Error, false)
                .addVariable("Warning", &Installmessage::Warning, false)
                .addVariable("User", &Installmessage::User, false)
                .addVariable("Info", &Installmessage::Info, false)
                .addVariable("Filesinuse", &Installmessage::Filesinuse, false)
                .addVariable("Resolvesource", &Installmessage::Resolvesource, false)
                .addVariable("Outofdiskspace", &Installmessage::Outofdiskspace, false)
                .addVariable("Actionstart", &Installmessage::Actionstart, false)
                .addVariable("Actiondata", &Installmessage::Actiondata, false)
                .addVariable("Progress", &Installmessage::Progress, false)
                .addVariable("Commondata", &Installmessage::Commondata, false)
                .addVariable("Initialize", &Installmessage::Initialize, false)
                .addVariable("Terminate", &Installmessage::Terminate, false)
                .addVariable("Showdialog", &Installmessage::Showdialog, false)
                .addVariable("Performance", &Installmessage::Performance, false)
                .addVariable("Rmfilesinuse", &Installmessage::Rmfilesinuse, false)
                .addVariable("Installstart", &Installmessage::Installstart, false)
                .addVariable("Installend", &Installmessage::Installend, false)
            .beginNamespace ("Installuilevel")
                .addVariable("Nochange", &Installuilevel::Nochange, false)
                .addVariable("Default", &Installuilevel::Default, false)
                .addVariable("None", &Installuilevel::None, false)
                .addVariable("Basic", &Installuilevel::Basic, false)
                .addVariable("Reduced", &Installuilevel::Reduced, false)
                .addVariable("Full", &Installuilevel::Full, false)
                .addVariable("Enddialog", &Installuilevel::Enddialog, false)
                .addVariable("Progressonly", &Installuilevel::Progressonly, false)
                .addVariable("Hidecancel", &Installuilevel::Hidecancel, false)
                .addVariable("Sourceresonly", &Installuilevel::Sourceresonly, false)
                .addVariable("Uaconly", &Installuilevel::Uaconly, false)
            .endNamespace ()
            .beginNamespace ("Installstate")
                .addVariable("Notused", &Installstate::Notused, false)
                .addVariable("Badconfig", &Installstate::Badconfig, false)
                .addVariable("Incomplete", &Installstate::Incomplete, false)
                .addVariable("Sourceabsent", &Installstate::Sourceabsent, false)
                .addVariable("Moredata", &Installstate::Moredata, false)
                .addVariable("Invalidarg", &Installstate::Invalidarg, false)
                .addVariable("Unknown", &Installstate::Unknown, false)
                .addVariable("Broken", &Installstate::Broken, false)
                .addVariable("Advertised", &Installstate::Advertised, false)
                .addVariable("Removed", &Installstate::Removed, false)
                .addVariable("Absent", &Installstate::Absent, false)
                .addVariable("Local", &Installstate::Local, false)
                .addVariable("Source", &Installstate::Source, false)
                .addVariable("Default", &Installstate::Default, false)
            .endNamespace ()
            .beginNamespace ("Userinfostate")
                .addVariable("Moredata", &Userinfostate::Moredata, false)
                .addVariable("Invalidarg", &Userinfostate::Invalidarg, false)
                .addVariable("Unknown", &Userinfostate::Unknown, false)
                .addVariable("Absent", &Userinfostate::Absent, false)
                .addVariable("Present", &Userinfostate::Present, false)
            .endNamespace ()
            .beginNamespace ("Installlevel")
                .addVariable("Default", &Installlevel::Default, false)
                .addVariable("Minimum", &Installlevel::Minimum, false)
                .addVariable("Maximum", &Installlevel::Maximum, false)
            .endNamespace ()
            .beginNamespace ("Reinstallmode")
                .addVariable("Repair", &Reinstallmode::Repair, false)
                .addVariable("Filemissing", &Reinstallmode::Filemissing, false)
                .addVariable("Fileolderversion", &Reinstallmode::Fileolderversion, false)
                .addVariable("Fileequalversion", &Reinstallmode::Fileequalversion, false)
                .addVariable("Fileexact", &Reinstallmode::Fileexact, false)
                .addVariable("Fileverify", &Reinstallmode::Fileverify, false)
                .addVariable("Filereplace", &Reinstallmode::Filereplace, false)
                .addVariable("Machinedata", &Reinstallmode::Machinedata, false)
                .addVariable("Userdata", &Reinstallmode::Userdata, false)
                .addVariable("Shortcut", &Reinstallmode::Shortcut, false)
                .addVariable("Package", &Reinstallmode::Package, false)
            .endNamespace ()
            .beginNamespace ("Installogmode")
                .addVariable("Fatalexit", &Installogmode::Fatalexit, false)
                .addVariable("Error", &Installogmode::Error, false)
                .addVariable("Warning", &Installogmode::Warning, false)
                .addVariable("User", &Installogmode::User, false)
                .addVariable("Info", &Installogmode::Info, false)
                .addVariable("Resolvesource", &Installogmode::Resolvesource, false)
                .addVariable("Outofdiskspace", &Installogmode::Outofdiskspace, false)
                .addVariable("Actionstart", &Installogmode::Actionstart, false)
                .addVariable("Actiondata", &Installogmode::Actiondata, false)
                .addVariable("Commondata", &Installogmode::Commondata, false)
                .addVariable("Propertydump", &Installogmode::Propertydump, false)
                .addVariable("Verbose", &Installogmode::Verbose, false)
                .addVariable("Extradebug", &Installogmode::Extradebug, false)
                .addVariable("Logonlyonerror", &Installogmode::Logonlyonerror, false)
                .addVariable("Logperformance", &Installogmode::Logperformance, false)
                .addVariable("Progress", &Installogmode::Progress, false)
                .addVariable("Initialize", &Installogmode::Initialize, false)
                .addVariable("Terminate", &Installogmode::Terminate, false)
                .addVariable("Showdialog", &Installogmode::Showdialog, false)
                .addVariable("Filesinuse", &Installogmode::Filesinuse, false)
                .addVariable("Rmfilesinuse", &Installogmode::Rmfilesinuse, false)
                .addVariable("Installstart", &Installogmode::Installstart, false)
                .addVariable("Installend", &Installogmode::Installend, false)
            .endNamespace ()
            .beginNamespace ("Installlogattributes")
                .addVariable("Append", &Installlogattributes::Append, false)
                .addVariable("Flusheachline", &Installlogattributes::Flusheachline, false)
            .endNamespace ()
            .beginNamespace ("Installfeatureattribute")
                .addVariable("Favorlocal", &Installfeatureattribute::Favorlocal, false)
                .addVariable("Favorsource", &Installfeatureattribute::Favorsource, false)
                .addVariable("Followparent", &Installfeatureattribute::Followparent, false)
                .addVariable("Favoradvertise", &Installfeatureattribute::Favoradvertise, false)
                .addVariable("Disallowadvertise", &Installfeatureattribute::Disallowadvertise, false)
                .addVariable("Nounsupportedadvertise", &Installfeatureattribute::Nounsupportedadvertise, false)
            .endNamespace ()
            .beginNamespace ("Installmode")
                .addVariable("Nodetection_any", &Installmode::Nodetection_any, false)
                .addVariable("Nosourceresolution", &Installmode::Nosourceresolution, false)
                .addVariable("Nodetection", &Installmode::Nodetection, false)
                .addVariable("Existing", &Installmode::Existing, false)
                .addVariable("Default", &Installmode::Default, false)
            .endNamespace ()
            .beginNamespace ("Msipatchstate")
                .addVariable("Invalid", &Msipatchstate::Invalid, false)
                .addVariable("Applied", &Msipatchstate::Applied, false)
                .addVariable("Superseded", &Msipatchstate::Superseded, false)
                .addVariable("Obsoleted", &Msipatchstate::Obsoleted, false)
                .addVariable("Registered", &Msipatchstate::Registered, false)
                .addVariable("All", &Msipatchstate::All, false)
            .endNamespace ()
            .beginNamespace ("Msiinstallcontext")
                .addVariable("Firstvisible", &Msiinstallcontext::Firstvisible, false)
                .addVariable("None", &Msiinstallcontext::None, false)
                .addVariable("Usermanaged", &Msiinstallcontext::Usermanaged, false)
                .addVariable("Userunmanaged", &Msiinstallcontext::Userunmanaged, false)
                .addVariable("Machine", &Msiinstallcontext::Machine, false)
                .addVariable("All", &Msiinstallcontext::All, false)
                .addVariable("Allusermanaged", &Msiinstallcontext::Allusermanaged, false)
            .endNamespace ()
            .beginNamespace ("Msipatchdatatype")
                .addVariable("Datatype_patchfile", &Msipatchdatatype::Datatype_patchfile, false)
                .addVariable("Datatype_xmlpath", &Msipatchdatatype::Datatype_xmlpath, false)
                .addVariable("Datatype_xmlblob", &Msipatchdatatype::Datatype_xmlblob, false)
            .endNamespace ()
            .beginNamespace ("Scriptflags")
                .addVariable("Cacheinfo", &Scriptflags::Cacheinfo, false)
                .addVariable("Shortcuts", &Scriptflags::Shortcuts, false)
                .addVariable("Machineassign", &Scriptflags::Machineassign, false)
                .addVariable("Regdata_cnfginfo", &Scriptflags::Regdata_cnfginfo, false)
                .addVariable("Validate_transforms_list", &Scriptflags::Validate_transforms_list, false)
                .addVariable("Regdata_classinfo", &Scriptflags::Regdata_classinfo, false)
                .addVariable("Regdata_extensioninfo", &Scriptflags::Regdata_extensioninfo, false)
                .addVariable("Regdata_appinfo", &Scriptflags::Regdata_appinfo, false)
                .addVariable("Regdata", &Scriptflags::Regdata, false)
            .endNamespace ()
            .beginNamespace ("Advertiseflags")
                .addVariable("Machineassign", &Advertiseflags::Machineassign, false)
                .addVariable("Userassign", &Advertiseflags::Userassign, false)
            .endNamespace ()
            .beginNamespace ("Installtype")
                .addVariable("Default", &Installtype::Default, false)
                .addVariable("Network_image", &Installtype::Network_image, false)
                .addVariable("Single_instance", &Installtype::Single_instance, false)
            .endNamespace ()
            .beginNamespace ("Msiarchitectureflags")
                .addVariable("X86", &Msiarchitectureflags::X86, false)
                .addVariable("Ia64", &Msiarchitectureflags::Ia64, false)
                .addVariable("AMD64", &Msiarchitectureflags::AMD64, false)
            .endNamespace ()
            .beginNamespace ("Msiopenpackageflags")
                .addVariable("Ignoremachinestate", &Msiopenpackageflags::Ignoremachinestate, false)
            .endNamespace ()
            .beginNamespace ("Msiadvertiseoptionflags")
                .addVariable("Instance", &Msiadvertiseoptionflags::Instance, false)
            .endNamespace ()
            .beginNamespace ("Msisourcetype")
                .addVariable("Unknown", &Msisourcetype::Unknown, false)
                .addVariable("Network", &Msisourcetype::Network, false)
                .addVariable("Url", &Msisourcetype::Url, false)
                .addVariable("Media", &Msisourcetype::Media, false)
            .endNamespace ()
            .beginNamespace ("Msicode")
                .addVariable("Product", &Msicode::Product, false)
                .addVariable("Patch", &Msicode::Patch, false)
            .endNamespace ()
            .beginNamespace ("Msitransaction")
                .addVariable("Chain_embeddedui", &Msitransaction::Chain_embeddedui, false)
                .addVariable("Join_existing_embeddedui", &Msitransaction::Join_existing_embeddedui, false)
            .endNamespace ()
            .beginNamespace ("Msitransactionstate")
                .addVariable("Rollback", &Msitransactionstate::Rollback, false)
                .addVariable("Commit", &Msitransactionstate::Commit, false)
            .endNamespace ()
            .beginNamespace ("Msidbstate")
                .addVariable("Error", &Msidbstate::Error, false)
                .addVariable("Read", &Msidbstate::Read, false)
                .addVariable("Write", &Msidbstate::Write, false)
            .endNamespace ()
            .beginNamespace ("Msimodify")
                .addVariable("Seek", &Msimodify::Seek, false)
                .addVariable("Refresh", &Msimodify::Refresh, false)
                .addVariable("Insert", &Msimodify::Insert, false)
                .addVariable("Update", &Msimodify::Update, false)
                .addVariable("Assign", &Msimodify::Assign, false)
                .addVariable("Replace", &Msimodify::Replace, false)
                .addVariable("Merge", &Msimodify::Merge, false)
                .addVariable("Delete", &Msimodify::Delete, false)
                .addVariable("Insert_temporary", &Msimodify::Insert_temporary, false)
                .addVariable("Validate", &Msimodify::Validate, false)
                .addVariable("Validate_new", &Msimodify::Validate_new, false)
                .addVariable("Validate_field", &Msimodify::Validate_field, false)
                .addVariable("Validate_delete", &Msimodify::Validate_delete, false)
            .endNamespace ()
            .beginNamespace ("Msicolinfo")
                .addVariable("Names", &Msicolinfo::Names, false)
                .addVariable("Types", &Msicolinfo::Types, false)
            .endNamespace ()
            .beginNamespace ("Msicondition")
                .addVariable("False", &Msicondition::False, false)
                .addVariable("True", &Msicondition::True, false)
                .addVariable("None", &Msicondition::None, false)
                .addVariable("Error", &Msicondition::Error, false)
            .endNamespace ()
            .beginNamespace ("Msicosttree")
                .addVariable("Selfonly", &Msicosttree::Selfonly, false)
                .addVariable("Children", &Msicosttree::Children, false)
                .addVariable("Parents", &Msicosttree::Parents, false)
                .addVariable("Reserved", &Msicosttree::Reserved, false)
            .endNamespace ()
            .beginNamespace ("Msidberror")
                .addVariable("Invalidarg", &Msidberror::Invalidarg, false)
                .addVariable("Moredata", &Msidberror::Moredata, false)
                .addVariable("Functionerror", &Msidberror::Functionerror, false)
                .addVariable("Noerror", &Msidberror::Noerror, false)
                .addVariable("Duplicatekey", &Msidberror::Duplicatekey, false)
                .addVariable("Required", &Msidberror::Required, false)
                .addVariable("Badlink", &Msidberror::Badlink, false)
                .addVariable("Overflow", &Msidberror::Overflow, false)
                .addVariable("Underflow", &Msidberror::Underflow, false)
                .addVariable("Notinset", &Msidberror::Notinset, false)
                .addVariable("Badversion", &Msidberror::Badversion, false)
                .addVariable("Badcase", &Msidberror::Badcase, false)
                .addVariable("Badguid", &Msidberror::Badguid, false)
                .addVariable("Badwildcard", &Msidberror::Badwildcard, false)
                .addVariable("Badidentifier", &Msidberror::Badidentifier, false)
                .addVariable("Badlanguage", &Msidberror::Badlanguage, false)
                .addVariable("Badfilename", &Msidberror::Badfilename, false)
                .addVariable("Badpath", &Msidberror::Badpath, false)
                .addVariable("Badcondition", &Msidberror::Badcondition, false)
                .addVariable("Badformatted", &Msidberror::Badformatted, false)
                .addVariable("Badtemplate", &Msidberror::Badtemplate, false)
                .addVariable("Baddefaultdir", &Msidberror::Baddefaultdir, false)
                .addVariable("Badregpath", &Msidberror::Badregpath, false)
                .addVariable("Badcustomsource", &Msidberror::Badcustomsource, false)
                .addVariable("Badproperty", &Msidberror::Badproperty, false)
                .addVariable("Missingdata", &Msidberror::Missingdata, false)
                .addVariable("Badcategory", &Msidberror::Badcategory, false)
                .addVariable("Badkeytable", &Msidberror::Badkeytable, false)
                .addVariable("Badmaxminvalues", &Msidberror::Badmaxminvalues, false)
                .addVariable("Badcabinet", &Msidberror::Badcabinet, false)
                .addVariable("Badshortcut", &Msidberror::Badshortcut, false)
                .addVariable("Stringoverflow", &Msidberror::Stringoverflow, false)
                .addVariable("Badlocalizeattrib", &Msidberror::Badlocalizeattrib, false)
            .endNamespace ()
            .beginNamespace ("Msirunmode")
                .addVariable("Admin", &Msirunmode::Admin, false)
                .addVariable("Advertise", &Msirunmode::Advertise, false)
                .addVariable("Maintenance", &Msirunmode::Maintenance, false)
                .addVariable("Rollbackenabled", &Msirunmode::Rollbackenabled, false)
                .addVariable("Logenabled", &Msirunmode::Logenabled, false)
                .addVariable("Operations", &Msirunmode::Operations, false)
                .addVariable("Rebootatend", &Msirunmode::Rebootatend, false)
                .addVariable("Rebootnow", &Msirunmode::Rebootnow, false)
                .addVariable("Cabinet", &Msirunmode::Cabinet, false)
                .addVariable("Sourceshortnames", &Msirunmode::Sourceshortnames, false)
                .addVariable("Targetshortnames", &Msirunmode::Targetshortnames, false)
                .addVariable("Reserved11", &Msirunmode::Reserved11, false)
                .addVariable("Windows9x", &Msirunmode::Windows9x, false)
                .addVariable("Zawenabled", &Msirunmode::Zawenabled, false)
                .addVariable("Reserved14", &Msirunmode::Reserved14, false)
                .addVariable("Reserved15", &Msirunmode::Reserved15, false)
                .addVariable("Scheduled", &Msirunmode::Scheduled, false)
                .addVariable("Rollback", &Msirunmode::Rollback, false)
                .addVariable("Commit", &Msirunmode::Commit, false)
            .endNamespace ()
            .beginNamespace ("Msitransform_error")
                .addVariable("Error_addexistingrow", &Msitransform_error::Error_addexistingrow, false)
                .addVariable("Error_delmissingrow", &Msitransform_error::Error_delmissingrow, false)
                .addVariable("Error_addexistingtable", &Msitransform_error::Error_addexistingtable, false)
                .addVariable("Error_delmissingtable", &Msitransform_error::Error_delmissingtable, false)
                .addVariable("Error_updatemissingrow", &Msitransform_error::Error_updatemissingrow, false)
                .addVariable("Error_changecodepage", &Msitransform_error::Error_changecodepage, false)
                .addVariable("Error_viewtransform", &Msitransform_error::Error_viewtransform, false)
            .endNamespace ()
            .beginNamespace ("Msitransform_validate")
                .addVariable("Validate_language", &Msitransform_validate::Validate_language, false)
                .addVariable("Validate_product", &Msitransform_validate::Validate_product, false)
                .addVariable("Validate_platform", &Msitransform_validate::Validate_platform, false)
                .addVariable("Validate_majorversion", &Msitransform_validate::Validate_majorversion, false)
                .addVariable("Validate_minorversion", &Msitransform_validate::Validate_minorversion, false)
                .addVariable("Validate_updateversion", &Msitransform_validate::Validate_updateversion, false)
                .addVariable("Validate_newlessbaseversion", &Msitransform_validate::Validate_newlessbaseversion, false)
                .addVariable("Validate_newlessequalbaseversion", &Msitransform_validate::Validate_newlessequalbaseversion, false)
                .addVariable("Validate_newequalbaseversion", &Msitransform_validate::Validate_newequalbaseversion, false)
                .addVariable("Validate_newgreaterequalbaseversion", &Msitransform_validate::Validate_newgreaterequalbaseversion, false)
                .addVariable("Validate_newgreaterbaseversion", &Msitransform_validate::Validate_newgreaterbaseversion, false)
                .addVariable("Validate_upgradecode", &Msitransform_validate::Validate_upgradecode, false)
            .endNamespace ()
            .beginNamespace ("Installproperty")
                .addVariable("Packagename", &Installproperty::Packagename, false)
                .addVariable("Transforms", &Installproperty::Transforms, false)
                .addVariable("Language", &Installproperty::Language, false)
                .addVariable("Productname", &Installproperty::Productname, false)
                .addVariable("Assignmenttype", &Installproperty::Assignmenttype, false)
                .addVariable("Instancetype", &Installproperty::Instancetype, false)
                .addVariable("Authorized_lua_app", &Installproperty::Authorized_lua_app, false)
                .addVariable("Packagecode", &Installproperty::Packagecode, false)
                .addVariable("Version", &Installproperty::Version, false)
                .addVariable("Producticon", &Installproperty::Producticon, false)
                .addVariable("Installedproductname", &Installproperty::Installedproductname, false)
                .addVariable("Versionstring", &Installproperty::Versionstring, false)
                .addVariable("Helplink", &Installproperty::Helplink, false)
                .addVariable("Helptelephone", &Installproperty::Helptelephone, false)
                .addVariable("Installlocation", &Installproperty::Installlocation, false)
                .addVariable("Installsource", &Installproperty::Installsource, false)
                .addVariable("Installdate", &Installproperty::Installdate, false)
                .addVariable("Publisher", &Installproperty::Publisher, false)
                .addVariable("Localpackage", &Installproperty::Localpackage, false)
                .addVariable("Urlinfoabout", &Installproperty::Urlinfoabout, false)
                .addVariable("Urlupdateinfo", &Installproperty::Urlupdateinfo, false)
                .addVariable("Versionminor", &Installproperty::Versionminor, false)
                .addVariable("Versionmajor", &Installproperty::Versionmajor, false)
                .addVariable("Productid", &Installproperty::Productid, false)
                .addVariable("Regcompany", &Installproperty::Regcompany, false)
                .addVariable("Regowner", &Installproperty::Regowner, false)
                .addVariable("Installedlanguage", &Installproperty::Installedlanguage, false)
                .addVariable("Uninstallable", &Installproperty::Uninstallable, false)
                .addVariable("Productstate", &Installproperty::Productstate, false)
                .addVariable("Patchstate", &Installproperty::Patchstate, false)
                .addVariable("Patchtype", &Installproperty::Patchtype, false)
                .addVariable("Luaenabled", &Installproperty::Luaenabled, false)
                .addVariable("Displayname", &Installproperty::Displayname, false)
                .addVariable("Moreinfourl", &Installproperty::Moreinfourl, false)
            .endNamespace ()
            .endNamespace ()
        .endNamespace ();

        getGlobalNamespace (aState)
        .beginNamespace ("Msi")
			.beginClass<MSIPATCHSEQUENCEINFO> ("Patchsequenceinfo")
				.addConstructor <void (*) (void)> ()
				.addData("PatchData", &MSIPATCHSEQUENCEINFO::szPatchData)
				.addData("PatchDataType", &MSIPATCHSEQUENCEINFO::ePatchDataType)
				.addData("Order", &MSIPATCHSEQUENCEINFO::dwOrder)
				.addData("Status", &MSIPATCHSEQUENCEINFO::uStatus)
			.endClass()
			.beginClass<MSIFILEHASHINFO> ("Filehashinfo")
				.addConstructor <void (*) (void)> ()
				.addData("FileHashInfoSize", &MSIFILEHASHINFO::dwFileHashInfoSize)
				.addProperty ("Data_0", &MsifilehashinfoHelper::get <0>, &MsifilehashinfoHelper::set <0>)
				.addProperty ("Data_1", &MsifilehashinfoHelper::get <1>, &MsifilehashinfoHelper::set <1>)
				.addProperty ("Data_2", &MsifilehashinfoHelper::get <2>, &MsifilehashinfoHelper::set <2>)
				.addProperty ("Data_3", &MsifilehashinfoHelper::get <3>, &MsifilehashinfoHelper::set <3>)
			.endClass()
			.beginClass<FILETIME> ("Filetime")
				.addConstructor <void (*) (void)> ()
                .addData("LowDateTime", &FILETIME::dwLowDateTime)
                .addData("HighDateTime", &FILETIME::dwHighDateTime)
			.endClass()
        .endNamespace ();

        getGlobalNamespace (aState)
        .beginNamespace ("Msi")
            .LF(CloseHandle)
            .LF(CloseAllHandles)
            .LF(EnableLog)
            .LF(QueryProductState)
            .LF(GetProductInfo)
            .LF(GetProductInfoEx)
            .LF(InstallProduct)
            .LF(ConfigureProduct)
            .LF(ConfigureProductEx)
            .LF(ReinstallProduct)
            .LF(AdvertiseProductEx)
            .LF(AdvertiseProduct)
            .LF(ProcessAdvertiseScript)
            .LF(AdvertiseScript)
            .LL(GetProductInfoFromScript)
            .LF(GetProductCode)
            .LL(GetUserInfo)
            .LF(CollectUserInfo)
            .LF(ApplyPatch)
            .LF(GetPatchInfo)
            .LL(EnumPatches)
            .LF(RemovePatches)
            .LF(ExtractPatchXMLData)
            .LF(GetPatchInfoEx)
            .LF(ApplyMultiplePatches)
            .LF(DeterminePatchSequence)
            .LF(DetermineApplicablePatches)
            .LF(EnumPatchesEx)
            .LF(QueryFeatureState)
            .LF(QueryFeatureStateEx)
            .LF(UseFeature)
            .LF(UseFeatureEx)
            .LF(GetFeatureUsage)
            .LF(ConfigureFeature)
            .LF(ReinstallFeature)
            .LF(ProvideComponent)
            .LF(ProvideQualifiedComponent)
            .LF(ProvideQualifiedComponentEx)
            .LF(GetComponentPath)
            .LF(ProvideAssembly)
            .LF(QueryComponentState)
            .LL(EnumProducts)
            .LL(EnumProductsEx)
            .LL(EnumRelatedProducts)
            .LL(EnumFeatures)
            .LL(EnumClients)
            .LL(EnumComponents)
            .LL(EnumComponentQualifiers)
            .LL(EnumComponentQualifiers)
            .LF(OpenProduct)
            .LF(OpenPackage)
            .LF(OpenPackageEx)
            .LL(GetPatchFileList)
            .LF(GetPatchFileListMsiGetProductProperty)
            .LF(VerifyPackage)
            .LL(GetFeatureInfo)
            .LF(InstallMissingComponent)
            .LF(InstallMissingFile)
            .LL(LocateComponent)
            .LF(SourceListClearAll)
            .LF(SourceListAddSource)
            .LF(SourceListForceResolution)
            .LF(SourceListAddSourceEx)
            .LF(SourceListAddMediaDisk)
            .LF(SourceListClearSource)
            .LF(SourceListClearMediaDisk)
            .LF(SourceListClearAllEx)
            .LF(SourceListForceResolutionEx)
            .LF(SourceListSetInfo)
            .LF(SourceListGetInfo)
            .LL(SourceListEnumSources)
            .LL(SourceListEnumMediaDisks)
            .LL(GetFileVersion)
            .LF(IsProductElevated)
            .LF(NotifySidChange)
            .LL(GetShortcutTarget)
            .LL(GetFileHash)
            .LL(GetFileSignatureInformation)
            .LL(BeginTransaction)
            .LF(EndTransaction)
            .LF(JoinTransaction)
            .LF(DatabaseOpenView)
            .LL(ViewGetError)
            .LF(ViewExecute)
            .LF(ViewFetch)
            .LF(ViewModify)
            .LF(ViewGetColumnInfo)
            .LF(ViewClose)
            .LF(DatabaseGetPrimaryKeys)
            .LF(DatabaseIsTablePersistent)
            .LF(GetSummaryInformation)
            .LF(SummaryInfoGetPropertyCount)
            .LL(SummaryInfoSetProperty)
            .LL(SummaryInfoGetProperty)
            .LF(SummaryInfoPersist)
            .LF(OpenDatabase)
            .LF(DatabaseImport)
            .LF(DatabaseExport)
            .LF(DatabaseMerge)
            .LF(DatabaseGenerateTransform)
            .LF(DatabaseApplyTransform)
            .LF(CreateTransformSummaryInfo)
            .LF(DatabaseCommit)
            .LF(CreateRecord)
            .LF(RecordIsNull)
            .LF(RecordDataSize)
            .LF(RecordGetInteger)
            .LF(RecordGetFieldCount)
            .LF(GetDatabaseState)
            .LF(RecordSetString)
            .LF(RecordGetString)
            .LF(RecordSetStream)
            .LF(RecordReadStream)
            .LF(RecordClearData)
            .LF(GetActiveDatabase)
            .LF(SetProperty)
            .LF(GetProperty)
            .LF(GetLanguage)
            .LF(GetMode)
            .LF(SetMode)
            .LF(FormatRecord)
            .LF(DoAction)
            .LF(Sequence)
            .LF(ProcessMessage)
            .LF(EvaluateCondition)
            .LL(GetFeatureState)
            .LF(SetFeatureState)
            .LF(SetFeatureAttributes)
            .LL(GetComponentState)
            .LF(SetComponentState)
            .LF(GetFeatureCost)
            .LF(SetInstallLevel)
            .LF(VerifyDiskSpace)
            .LF(GetFeatureValidStates)
            .LL(EnumComponentCosts)
            .LF(GetSourcePath)
            .LF(GetTargetPath)
            .LF(SetTargetPath)
            .LF(GetLastErrorRecord)
            .LF(EnableUIPreview)
            .LF(PreviewDialog)
            .LF(PreviewBillboardA)
        .endNamespace ();
}
